├── .devcontainer ├── Dockerfile ├── README.md └── devcontainer.json ├── .fixtures.yml ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── codespell.yml │ └── tests.yml ├── .gitignore ├── .pdkignore ├── .puppet-lint.rc ├── .rspec ├── .rubocop.yml ├── .rubocop_todo.yml ├── .sync.yml ├── .vscode └── extensions.json ├── CHANGELOG.md ├── Gemfile ├── HISTORY.md ├── LICENSE ├── README.md ├── Rakefile ├── Rakefile.local ├── files ├── limits.conf └── profile.conf ├── kitchen.do.yml ├── kitchen.yml ├── lib ├── facter │ ├── home_users.rb │ ├── manage_access.rb │ └── retrieve_system_users.rb └── puppet │ └── functions │ └── combine_sugid_lists.rb ├── manifests ├── blacklist_files.pp ├── grub.pp ├── init.pp ├── limits.pp ├── login_defs.pp ├── minimize_access.pp ├── modules.pp ├── pam.pp ├── profile.pp ├── securetty.pp ├── services.pp ├── suid_sgid.pp ├── sysctl.pp └── umask.pp ├── metadata.json ├── pdk.yaml ├── renovate.json ├── spec ├── classes │ ├── os_hardening_spec.rb │ └── sysctl_spec.rb ├── default_facts.yml ├── fixtures │ └── etc │ │ └── login.defs ├── functions │ └── combine_sugid_lists_spec.rb ├── spec_helper.rb └── unit │ └── facter │ ├── home_users_spec.rb │ └── retrieve_system_users_spec.rb ├── templates ├── disable_fs.erb ├── grub_hardening.erb ├── login.defs.erb ├── modules.erb ├── pam_passwdqc.erb ├── pam_su_debian_ubuntu.erb ├── pam_tally2.erb ├── pam_unix.erb ├── remove_sugid_bits.erb ├── securetty.erb └── umask.sh.erb ├── test ├── fixtures │ ├── Puppetfile │ ├── manifests.do │ │ └── site.pp │ ├── manifests │ │ └── site.pp │ └── metadata.json └── integration │ ├── digitalocean-linux-baseline │ ├── controls │ │ └── tests.rb │ └── inspec.yml │ └── docker-linux-baseline │ ├── controls │ └── tests.rb │ └── inspec.yml └── tools └── fix_permissions /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM puppet/pdk:latest 2 | 3 | # [Optional] Uncomment this section to install additional packages. 4 | # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 5 | # && apt-get -y install --no-install-recommends 6 | 7 | -------------------------------------------------------------------------------- /.devcontainer/README.md: -------------------------------------------------------------------------------- 1 | # devcontainer 2 | 3 | 4 | For format details, see https://aka.ms/devcontainer.json. 5 | 6 | For config options, see the README at: 7 | https://github.com/microsoft/vscode-dev-containers/tree/v0.140.1/containers/puppet 8 | 9 | ``` json 10 | { 11 | "name": "Puppet Development Kit (Community)", 12 | "dockerFile": "Dockerfile", 13 | 14 | // Set *default* container specific settings.json values on container create. 15 | "settings": { 16 | "terminal.integrated.shell.linux": "/bin/bash" 17 | }, 18 | 19 | // Add the IDs of extensions you want installed when the container is created. 20 | "extensions": [ 21 | "puppet.puppet-vscode", 22 | "rebornix.Ruby" 23 | ] 24 | 25 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 26 | "forwardPorts": [], 27 | 28 | // Use 'postCreateCommand' to run commands after the container is created. 29 | "postCreateCommand": "pdk --version", 30 | } 31 | ``` 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Puppet Development Kit (Community)", 3 | "dockerFile": "Dockerfile", 4 | 5 | "settings": { 6 | "terminal.integrated.profiles.linux": { 7 | "bash": { 8 | "path": "bash", 9 | } 10 | } 11 | }, 12 | 13 | "extensions": [ 14 | "puppet.puppet-vscode", 15 | "rebornix.Ruby" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.fixtures.yml: -------------------------------------------------------------------------------- 1 | fixtures: 2 | repositories: 3 | sysctl: https://github.com/hercules-team/augeasproviders_sysctl 4 | augeasproviders_core: https://github.com/hercules-team/augeasproviders_core 5 | stdlib: https://github.com/puppetlabs/puppetlabs-stdlib 6 | 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.rb eol=lf 2 | *.erb eol=lf 3 | *.pp eol=lf 4 | *.sh eol=lf 5 | *.epp eol=lf 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **Expected behavior** 11 | A clear and concise description of what you expected to happen. 12 | 13 | **Actual behavior** 14 | 15 | ```paste below 16 | 17 | ``` 18 | 19 | **Example code** 20 | 21 | ```paste below 22 | 23 | ``` 24 | 25 | **OS / Environment** 26 | 27 | 28 | **Puppet Version** 29 | 30 | ```paste below 31 | 32 | ``` 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.github/workflows/codespell.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Codespell - Spellcheck 3 | 4 | on: # yamllint disable-line rule:truthy 5 | push: 6 | branches: [master] 7 | pull_request: 8 | branches: [master] 9 | 10 | jobs: 11 | codespell: 12 | uses: "dev-sec/.github/.github/workflows/codespell.yml@main" 13 | with: 14 | skip: "./.git,./Gemfile" -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | schedule: 9 | - cron: '0 4 * * *' 10 | 11 | jobs: 12 | syntax-lint: 13 | runs-on: ubuntu-latest 14 | env: 15 | SIMPLECOV: yes 16 | PUPPET_GEM_VERSION: "~> 7.0" 17 | strategy: 18 | fail-fast: false 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | - name: Set up Ruby 23 | uses: ruby/setup-ruby@v1 24 | with: 25 | ruby-version: 2.7 26 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically 27 | - name: Run tests 28 | run: bundle exec rake syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop 29 | 30 | unit: 31 | runs-on: ubuntu-latest 32 | env: 33 | SIMPLECOV: yes 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | include: 38 | - rvm: 2.7 39 | puppet_gem_version: "~> 7.0" 40 | steps: 41 | - uses: actions/checkout@v4 42 | - name: Set up Ruby 43 | uses: ruby/setup-ruby@v1 44 | with: 45 | ruby-version: ${{ matrix.rvm }} 46 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically 47 | env: 48 | PUPPET_GEM_VERSION: ${{ matrix.puppet_gem_version }} 49 | - name: Run tests 50 | run: bundle exec rake parallel_spec 51 | env: 52 | PUPPET_GEM_VERSION: ${{ matrix.puppet_gem_version }} 53 | 54 | integration: 55 | runs-on: ubuntu-latest 56 | env: 57 | SIMPLECOV: yes 58 | strategy: 59 | fail-fast: false 60 | matrix: 61 | version_os_puppet: 62 | - centos-7-puppet6 63 | - centos-7-puppet7 64 | - centos-8-puppet6 65 | - centos-8-puppet7 66 | - debian-10-puppet6 67 | - debian-10-puppet7 68 | - opensuse-15-puppet6 69 | - opensuse-15-puppet7 70 | - oracle-7-puppet6 71 | - oracle-7-puppet7 72 | - ubuntu-18-04-puppet6 73 | - ubuntu-18-04-puppet7 74 | - ubuntu-20-04-puppet6 75 | - ubuntu-20-04-puppet7 76 | steps: 77 | - uses: actions/checkout@v4 78 | - name: Set up Ruby 79 | uses: ruby/setup-ruby@v1 80 | with: 81 | ruby-version: 2.7 82 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically 83 | - name: Run tests 84 | run: bundle exec rake kitchen 85 | env: 86 | INSTANCE: ${{ matrix.version_os_puppet }} 87 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | .*.sw[op] 3 | .metadata 4 | .yardoc 5 | .yardwarns 6 | *.iml 7 | /.bundle/ 8 | /.idea/ 9 | /.vagrant/ 10 | /coverage/ 11 | /bin/ 12 | /doc/ 13 | /Gemfile.local 14 | /Gemfile.lock 15 | /junit/ 16 | /log/ 17 | /pkg/ 18 | /spec/fixtures/manifests/ 19 | /spec/fixtures/modules/ 20 | /tmp/ 21 | /vendor/ 22 | /convert_report.txt 23 | /update_report.txt 24 | .DS_Store 25 | .project 26 | .envrc 27 | /inventory.yaml 28 | /spec/fixtures/litmus_inventory.yaml 29 | /.kitchen/ 30 | /test/fixtures/.librarian/ 31 | /test/fixtures/.tmp/ 32 | /test/fixtures/Puppetfile.lock 33 | /kitchen.local.yml 34 | -------------------------------------------------------------------------------- /.pdkignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | .*.sw[op] 3 | .metadata 4 | .yardoc 5 | .yardwarns 6 | *.iml 7 | /.bundle/ 8 | /.idea/ 9 | /.vagrant/ 10 | /coverage/ 11 | /bin/ 12 | /doc/ 13 | /Gemfile.local 14 | /Gemfile.lock 15 | /junit/ 16 | /log/ 17 | /pkg/ 18 | /spec/fixtures/manifests/ 19 | /spec/fixtures/modules/ 20 | /tmp/ 21 | /vendor/ 22 | /convert_report.txt 23 | /update_report.txt 24 | .DS_Store 25 | .project 26 | .envrc 27 | /inventory.yaml 28 | /spec/fixtures/litmus_inventory.yaml 29 | /appveyor.yml 30 | /.editorconfig 31 | /.fixtures.yml 32 | /Gemfile 33 | /.gitattributes 34 | /.gitignore 35 | /.gitlab-ci.yml 36 | /.pdkignore 37 | /.puppet-lint.rc 38 | /Rakefile 39 | /rakelib/ 40 | /.rspec 41 | /.rubocop.yml 42 | /.travis.yml 43 | /.yardopts 44 | /spec/ 45 | /.vscode/ 46 | /.sync.yml 47 | /.devcontainer/ 48 | /.kitchen/ 49 | /test/fixtures/.librarian/ 50 | /test/fixtures/.tmp/ 51 | /test/fixtures/Puppetfile.lock 52 | -------------------------------------------------------------------------------- /.puppet-lint.rc: -------------------------------------------------------------------------------- 1 | --relative 2 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --format documentation 3 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | require: 3 | - rubocop-performance 4 | - rubocop-rspec 5 | AllCops: 6 | DisplayCopNames: true 7 | TargetRubyVersion: '2.4' 8 | Include: 9 | - "**/*.rb" 10 | Exclude: 11 | - bin/* 12 | - ".vendor/**/*" 13 | - "**/Gemfile" 14 | - "**/Rakefile" 15 | - pkg/**/* 16 | - spec/fixtures/**/* 17 | - vendor/**/* 18 | - "**/Puppetfile" 19 | - "**/Vagrantfile" 20 | - "**/Guardfile" 21 | Layout/LineLength: 22 | Description: People have wide screens, use them. 23 | Max: 200 24 | RSpec/BeforeAfterAll: 25 | Description: Beware of using after(:all) as it may cause state to leak between tests. 26 | A necessary evil in acceptance testing. 27 | Exclude: 28 | - spec/acceptance/**/*.rb 29 | RSpec/HookArgument: 30 | Description: Prefer explicit :each argument, matching existing module's style 31 | EnforcedStyle: each 32 | RSpec/DescribeSymbol: 33 | Exclude: 34 | - spec/unit/facter/**/*.rb 35 | Style/BlockDelimiters: 36 | Description: Prefer braces for chaining. Mostly an aesthetical choice. Better to 37 | be consistent then. 38 | EnforcedStyle: braces_for_chaining 39 | Style/ClassAndModuleChildren: 40 | Description: Compact style reduces the required amount of indentation. 41 | EnforcedStyle: compact 42 | Style/EmptyElse: 43 | Description: Enforce against empty else clauses, but allow `nil` for clarity. 44 | EnforcedStyle: empty 45 | Style/FormatString: 46 | Description: Following the main puppet project's style, prefer the % format format. 47 | EnforcedStyle: percent 48 | Style/FormatStringToken: 49 | Description: Following the main puppet project's style, prefer the simpler template 50 | tokens over annotated ones. 51 | EnforcedStyle: template 52 | Style/Lambda: 53 | Description: Prefer the keyword for easier discoverability. 54 | EnforcedStyle: literal 55 | Style/RegexpLiteral: 56 | Description: Community preference. See https://github.com/voxpupuli/modulesync_config/issues/168 57 | EnforcedStyle: percent_r 58 | Style/TernaryParentheses: 59 | Description: Checks for use of parentheses around ternary conditions. Enforce parentheses 60 | on complex expressions for better readability, but seriously consider breaking 61 | it up. 62 | EnforcedStyle: require_parentheses_when_complex 63 | Style/TrailingCommaInArguments: 64 | Description: Prefer always trailing comma on multiline argument lists. This makes 65 | diffs, and re-ordering nicer. 66 | EnforcedStyleForMultiline: comma 67 | Style/TrailingCommaInArrayLiteral: 68 | Description: Prefer always trailing comma on multiline literals. This makes diffs, 69 | and re-ordering nicer. 70 | EnforcedStyleForMultiline: comma 71 | Style/SymbolArray: 72 | Description: Using percent style obscures symbolic intent of array's contents. 73 | EnforcedStyle: brackets 74 | inherit_from: ".rubocop_todo.yml" 75 | RSpec/MessageSpies: 76 | EnforcedStyle: receive 77 | Style/Documentation: 78 | Exclude: 79 | - lib/puppet/parser/functions/**/* 80 | - spec/**/* 81 | Style/WordArray: 82 | EnforcedStyle: brackets 83 | Performance/AncestorsInclude: 84 | Enabled: true 85 | Performance/BigDecimalWithNumericArgument: 86 | Enabled: true 87 | Performance/BlockGivenWithExplicitBlock: 88 | Enabled: true 89 | Performance/CaseWhenSplat: 90 | Enabled: true 91 | Performance/ConstantRegexp: 92 | Enabled: true 93 | Performance/MethodObjectAsBlock: 94 | Enabled: true 95 | Performance/RedundantSortBlock: 96 | Enabled: true 97 | Performance/RedundantStringChars: 98 | Enabled: true 99 | Performance/ReverseFirst: 100 | Enabled: true 101 | Performance/SortReverse: 102 | Enabled: true 103 | Performance/Squeeze: 104 | Enabled: true 105 | Performance/StringInclude: 106 | Enabled: true 107 | Performance/Sum: 108 | Enabled: true 109 | Style/CollectionMethods: 110 | Enabled: true 111 | Style/MethodCalledOnDoEndBlock: 112 | Enabled: true 113 | Style/StringMethods: 114 | Enabled: true 115 | Bundler/InsecureProtocolSource: 116 | Enabled: false 117 | Gemspec/DuplicatedAssignment: 118 | Enabled: false 119 | Gemspec/OrderedDependencies: 120 | Enabled: false 121 | Gemspec/RequiredRubyVersion: 122 | Enabled: false 123 | Gemspec/RubyVersionGlobalsUsage: 124 | Enabled: false 125 | Layout/ArgumentAlignment: 126 | Enabled: false 127 | Layout/BeginEndAlignment: 128 | Enabled: false 129 | Layout/ClosingHeredocIndentation: 130 | Enabled: false 131 | Layout/EmptyComment: 132 | Enabled: false 133 | Layout/EmptyLineAfterGuardClause: 134 | Enabled: false 135 | Layout/EmptyLinesAroundArguments: 136 | Enabled: false 137 | Layout/EmptyLinesAroundAttributeAccessor: 138 | Enabled: false 139 | Layout/EndOfLine: 140 | Enabled: false 141 | Layout/FirstArgumentIndentation: 142 | Enabled: false 143 | Layout/HashAlignment: 144 | Enabled: false 145 | Layout/HeredocIndentation: 146 | Enabled: false 147 | Layout/LeadingEmptyLines: 148 | Enabled: false 149 | Layout/SpaceAroundMethodCallOperator: 150 | Enabled: false 151 | Layout/SpaceInsideArrayLiteralBrackets: 152 | Enabled: false 153 | Layout/SpaceInsideReferenceBrackets: 154 | Enabled: false 155 | Lint/BigDecimalNew: 156 | Enabled: false 157 | Lint/BooleanSymbol: 158 | Enabled: false 159 | Lint/ConstantDefinitionInBlock: 160 | Enabled: false 161 | Lint/DeprecatedOpenSSLConstant: 162 | Enabled: false 163 | Lint/DisjunctiveAssignmentInConstructor: 164 | Enabled: false 165 | Lint/DuplicateElsifCondition: 166 | Enabled: false 167 | Lint/DuplicateRequire: 168 | Enabled: false 169 | Lint/DuplicateRescueException: 170 | Enabled: false 171 | Lint/EmptyConditionalBody: 172 | Enabled: false 173 | Lint/EmptyFile: 174 | Enabled: false 175 | Lint/ErbNewArguments: 176 | Enabled: false 177 | Lint/FloatComparison: 178 | Enabled: false 179 | Lint/HashCompareByIdentity: 180 | Enabled: false 181 | Lint/IdentityComparison: 182 | Enabled: false 183 | Lint/InterpolationCheck: 184 | Enabled: false 185 | Lint/MissingCopEnableDirective: 186 | Enabled: false 187 | Lint/MixedRegexpCaptureTypes: 188 | Enabled: false 189 | Lint/NestedPercentLiteral: 190 | Enabled: false 191 | Lint/NonDeterministicRequireOrder: 192 | Enabled: false 193 | Lint/OrderedMagicComments: 194 | Enabled: false 195 | Lint/OutOfRangeRegexpRef: 196 | Enabled: false 197 | Lint/RaiseException: 198 | Enabled: false 199 | Lint/RedundantCopEnableDirective: 200 | Enabled: false 201 | Lint/RedundantRequireStatement: 202 | Enabled: false 203 | Lint/RedundantSafeNavigation: 204 | Enabled: false 205 | Lint/RedundantWithIndex: 206 | Enabled: false 207 | Lint/RedundantWithObject: 208 | Enabled: false 209 | Lint/RegexpAsCondition: 210 | Enabled: false 211 | Lint/ReturnInVoidContext: 212 | Enabled: false 213 | Lint/SafeNavigationConsistency: 214 | Enabled: false 215 | Lint/SafeNavigationWithEmpty: 216 | Enabled: false 217 | Lint/SelfAssignment: 218 | Enabled: false 219 | Lint/SendWithMixinArgument: 220 | Enabled: false 221 | Lint/ShadowedArgument: 222 | Enabled: false 223 | Lint/StructNewOverride: 224 | Enabled: false 225 | Lint/ToJSON: 226 | Enabled: false 227 | Lint/TopLevelReturnWithArgument: 228 | Enabled: false 229 | Lint/TrailingCommaInAttributeDeclaration: 230 | Enabled: false 231 | Lint/UnreachableLoop: 232 | Enabled: false 233 | Lint/UriEscapeUnescape: 234 | Enabled: false 235 | Lint/UriRegexp: 236 | Enabled: false 237 | Lint/UselessMethodDefinition: 238 | Enabled: false 239 | Lint/UselessTimes: 240 | Enabled: false 241 | Metrics/AbcSize: 242 | Enabled: false 243 | Metrics/BlockLength: 244 | Enabled: false 245 | Metrics/BlockNesting: 246 | Enabled: false 247 | Metrics/ClassLength: 248 | Enabled: false 249 | Metrics/CyclomaticComplexity: 250 | Enabled: false 251 | Metrics/MethodLength: 252 | Enabled: false 253 | Metrics/ModuleLength: 254 | Enabled: false 255 | Metrics/ParameterLists: 256 | Enabled: false 257 | Metrics/PerceivedComplexity: 258 | Enabled: false 259 | Migration/DepartmentName: 260 | Enabled: false 261 | Naming/AccessorMethodName: 262 | Enabled: false 263 | Naming/BlockParameterName: 264 | Enabled: false 265 | Naming/HeredocDelimiterCase: 266 | Enabled: false 267 | Naming/HeredocDelimiterNaming: 268 | Enabled: false 269 | Naming/MemoizedInstanceVariableName: 270 | Enabled: false 271 | Naming/MethodParameterName: 272 | Enabled: false 273 | Naming/RescuedExceptionsVariableName: 274 | Enabled: false 275 | Naming/VariableNumber: 276 | Enabled: false 277 | Performance/BindCall: 278 | Enabled: false 279 | Performance/DeletePrefix: 280 | Enabled: false 281 | Performance/DeleteSuffix: 282 | Enabled: false 283 | Performance/InefficientHashSearch: 284 | Enabled: false 285 | Performance/UnfreezeString: 286 | Enabled: false 287 | Performance/UriDefaultParser: 288 | Enabled: false 289 | RSpec/Be: 290 | Enabled: false 291 | RSpec/Capybara/CurrentPathExpectation: 292 | Enabled: false 293 | RSpec/Capybara/FeatureMethods: 294 | Enabled: false 295 | RSpec/Capybara/VisibilityMatcher: 296 | Enabled: false 297 | RSpec/ContextMethod: 298 | Enabled: false 299 | RSpec/ContextWording: 300 | Enabled: false 301 | RSpec/DescribeClass: 302 | Enabled: false 303 | RSpec/EmptyHook: 304 | Enabled: false 305 | RSpec/EmptyLineAfterExample: 306 | Enabled: false 307 | RSpec/EmptyLineAfterExampleGroup: 308 | Enabled: false 309 | RSpec/EmptyLineAfterHook: 310 | Enabled: false 311 | RSpec/ExampleLength: 312 | Enabled: false 313 | RSpec/ExampleWithoutDescription: 314 | Enabled: false 315 | RSpec/ExpectChange: 316 | Enabled: false 317 | RSpec/ExpectInHook: 318 | Enabled: false 319 | RSpec/FactoryBot/AttributeDefinedStatically: 320 | Enabled: false 321 | RSpec/FactoryBot/CreateList: 322 | Enabled: false 323 | RSpec/FactoryBot/FactoryClassName: 324 | Enabled: false 325 | RSpec/HooksBeforeExamples: 326 | Enabled: false 327 | RSpec/ImplicitBlockExpectation: 328 | Enabled: false 329 | RSpec/ImplicitSubject: 330 | Enabled: false 331 | RSpec/LeakyConstantDeclaration: 332 | Enabled: false 333 | RSpec/LetBeforeExamples: 334 | Enabled: false 335 | RSpec/MissingExampleGroupArgument: 336 | Enabled: false 337 | RSpec/MultipleExpectations: 338 | Enabled: false 339 | RSpec/MultipleMemoizedHelpers: 340 | Enabled: false 341 | RSpec/MultipleSubjects: 342 | Enabled: false 343 | RSpec/NestedGroups: 344 | Enabled: false 345 | RSpec/PredicateMatcher: 346 | Enabled: false 347 | RSpec/ReceiveCounts: 348 | Enabled: false 349 | RSpec/ReceiveNever: 350 | Enabled: false 351 | RSpec/RepeatedExampleGroupBody: 352 | Enabled: false 353 | RSpec/RepeatedExampleGroupDescription: 354 | Enabled: false 355 | RSpec/RepeatedIncludeExample: 356 | Enabled: false 357 | RSpec/ReturnFromStub: 358 | Enabled: false 359 | RSpec/SharedExamples: 360 | Enabled: false 361 | RSpec/StubbedMock: 362 | Enabled: false 363 | RSpec/UnspecifiedException: 364 | Enabled: false 365 | RSpec/VariableDefinition: 366 | Enabled: false 367 | RSpec/VoidExpect: 368 | Enabled: false 369 | RSpec/Yield: 370 | Enabled: false 371 | Security/Open: 372 | Enabled: false 373 | Style/AccessModifierDeclarations: 374 | Enabled: false 375 | Style/AccessorGrouping: 376 | Enabled: false 377 | Style/AsciiComments: 378 | Enabled: false 379 | Style/BisectedAttrAccessor: 380 | Enabled: false 381 | Style/CaseLikeIf: 382 | Enabled: false 383 | Style/ClassEqualityComparison: 384 | Enabled: false 385 | Style/ColonMethodDefinition: 386 | Enabled: false 387 | Style/CombinableLoops: 388 | Enabled: false 389 | Style/CommentedKeyword: 390 | Enabled: false 391 | Style/Dir: 392 | Enabled: false 393 | Style/DoubleCopDisableDirective: 394 | Enabled: false 395 | Style/EmptyBlockParameter: 396 | Enabled: false 397 | Style/EmptyLambdaParameter: 398 | Enabled: false 399 | Style/Encoding: 400 | Enabled: false 401 | Style/EvalWithLocation: 402 | Enabled: false 403 | Style/ExpandPathArguments: 404 | Enabled: false 405 | Style/ExplicitBlockArgument: 406 | Enabled: false 407 | Style/ExponentialNotation: 408 | Enabled: false 409 | Style/FloatDivision: 410 | Enabled: false 411 | Style/FrozenStringLiteralComment: 412 | Enabled: false 413 | Style/GlobalStdStream: 414 | Enabled: false 415 | Style/HashAsLastArrayItem: 416 | Enabled: false 417 | Style/HashLikeCase: 418 | Enabled: false 419 | Style/HashTransformKeys: 420 | Enabled: false 421 | Style/HashTransformValues: 422 | Enabled: false 423 | Style/IfUnlessModifier: 424 | Enabled: false 425 | Style/KeywordParametersOrder: 426 | Enabled: false 427 | Style/MinMax: 428 | Enabled: false 429 | Style/MixinUsage: 430 | Enabled: false 431 | Style/MultilineWhenThen: 432 | Enabled: false 433 | Style/NegatedUnless: 434 | Enabled: false 435 | Style/NumericPredicate: 436 | Enabled: false 437 | Style/OptionalBooleanParameter: 438 | Enabled: false 439 | Style/OrAssignment: 440 | Enabled: false 441 | Style/RandomWithOffset: 442 | Enabled: false 443 | Style/RedundantAssignment: 444 | Enabled: false 445 | Style/RedundantCondition: 446 | Enabled: false 447 | Style/RedundantConditional: 448 | Enabled: false 449 | Style/RedundantFetchBlock: 450 | Enabled: false 451 | Style/RedundantFileExtensionInRequire: 452 | Enabled: false 453 | Style/RedundantRegexpCharacterClass: 454 | Enabled: false 455 | Style/RedundantRegexpEscape: 456 | Enabled: false 457 | Style/RedundantSelfAssignment: 458 | Enabled: false 459 | Style/RedundantSort: 460 | Enabled: false 461 | Style/RescueStandardError: 462 | Enabled: false 463 | Style/SingleArgumentDig: 464 | Enabled: false 465 | Style/SlicingWithRange: 466 | Enabled: false 467 | Style/SoleNestedConditional: 468 | Enabled: false 469 | Style/StderrPuts: 470 | Enabled: false 471 | Style/StringConcatenation: 472 | Enabled: false 473 | Style/Strip: 474 | Enabled: false 475 | Style/SymbolProc: 476 | Enabled: false 477 | Style/TrailingBodyOnClass: 478 | Enabled: false 479 | Style/TrailingBodyOnMethodDefinition: 480 | Enabled: false 481 | Style/TrailingBodyOnModule: 482 | Enabled: false 483 | Style/TrailingCommaInHashLiteral: 484 | Enabled: false 485 | Style/TrailingMethodEndStatement: 486 | Enabled: false 487 | Style/UnpackFirst: 488 | Enabled: false 489 | Lint/DuplicateBranch: 490 | Enabled: false 491 | Lint/DuplicateRegexpCharacterClassElement: 492 | Enabled: false 493 | Lint/EmptyBlock: 494 | Enabled: false 495 | Lint/EmptyClass: 496 | Enabled: false 497 | Lint/NoReturnInBeginEndBlocks: 498 | Enabled: false 499 | Lint/ToEnumArguments: 500 | Enabled: false 501 | Lint/UnexpectedBlockArity: 502 | Enabled: false 503 | Lint/UnmodifiedReduceAccumulator: 504 | Enabled: false 505 | Performance/CollectionLiteralInLoop: 506 | Enabled: false 507 | Style/ArgumentsForwarding: 508 | Enabled: false 509 | Style/CollectionCompact: 510 | Enabled: false 511 | Style/DocumentDynamicEvalDefinition: 512 | Enabled: false 513 | Style/NegatedIfElseCondition: 514 | Enabled: false 515 | Style/NilLambda: 516 | Enabled: false 517 | Style/RedundantArgument: 518 | Enabled: false 519 | Style/SwapValues: 520 | Enabled: false 521 | -------------------------------------------------------------------------------- /.rubocop_todo.yml: -------------------------------------------------------------------------------- 1 | --- 2 | Style/WordArray: 3 | Enabled: false 4 | -------------------------------------------------------------------------------- /.sync.yml: -------------------------------------------------------------------------------- 1 | --- 2 | .gitignore: 3 | paths: 4 | - '/.kitchen/' 5 | - '/test/fixtures/.librarian/' 6 | - '/test/fixtures/.tmp/' 7 | - '/test/fixtures/Puppetfile.lock' 8 | - '/kitchen.local.yml' 9 | 10 | .gitlab-ci.yml: 11 | delete: true 12 | 13 | .pdkignore: 14 | paths: 15 | - '/.kitchen/' 16 | - '/test/fixtures/.librarian/' 17 | - '/test/fixtures/.tmp/' 18 | - '/test/fixtures/Puppetfile.lock' 19 | 20 | .rubocop.yml: 21 | default_configs: 22 | inherit_from: .rubocop_todo.yml 23 | 24 | .travis.yml: 25 | delete: true 26 | 27 | .yardopts: 28 | delete: true 29 | 30 | appveyor.yml: 31 | delete: true 32 | 33 | Gemfile: 34 | required: 35 | ':integration': 36 | - gem: 'librarian-puppet' 37 | - gem: 'test-kitchen' 38 | - gem: 'kitchen-digitalocean' 39 | - gem: 'kitchen-docker' 40 | git: 'https://github.com/test-kitchen/kitchen-docker' 41 | - gem: 'kitchen-inspec' 42 | - gem: 'kitchen-puppet' 43 | - gem: 'kitchen-sync' 44 | - gem: 'inspec' 45 | source: 'https://packagecloud.io/cinc-project/stable' 46 | - gem: 'inspec-core' 47 | source: 'https://packagecloud.io/cinc-project/stable' 48 | - gem: 'chef-utils' 49 | source: 'https://rubygems.org/' 50 | - gem: 'chef-config' 51 | source: 'https://rubygems.org/' 52 | - gem: 'unf_ext' 53 | source: 'https://rubygems.org/' 54 | - gem: 'sync' 55 | source: 'https://rubygems.org/' 56 | optional: 57 | ':development': 58 | - gem: 'github_changelog_generator' 59 | condition: "Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.3.0')" 60 | 61 | Rakefile: 62 | changelog_user: 'dev-sec' 63 | changelog_project: 'puppet-os-hardening' 64 | changelog_since_tag: '1.1.1' 65 | imports: 66 | - 'Rakefile.local' 67 | 68 | data/common.yaml: 69 | delete: true 70 | 71 | hiera.yaml: 72 | delete: true 73 | 74 | spec/default_facts.yml: 75 | extra_facts: 76 | retrieve_system_users: 'root,bin,daemon,adm,lp,sync,shutdown,halt,mail,operator,games,ftp,nobody,systemd-network,dbus,polkitd,rpc,rpcuser,postfix,sshd,chrony' 77 | home_users: '' 78 | 79 | spec/spec_helper.rb: 80 | mock_with: ':rspec' 81 | 82 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "puppet.puppet-vscode", 4 | "rebornix.Ruby" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Changelog generator still broken, sorry 4 | 5 | ### Changes in v2.4.0 6 | 7 | - Compatibility for Puppet version 8 8 | 9 | ### Changes in v2.3.3 10 | 11 | - fix CI: use docker driver for transferring files \(\#290\) 12 | - Disable new check 'os-14' for automated testing \(\#291\) 13 | - Restore ability to override /etc/shadow file permissions and group owner \(\#293\) 14 | - move to CentOS 8 Stream from quay.io \(\#295\) 15 | - fix(pam_passwdqc): remove accidental paste from `pam_passwdqc.erb` \(\#299\) 16 | 17 | ### Changes in v2.3.2 18 | 19 | - Backwards incompatible breaking change in PR279 [\#284](https://github.com/dev-sec/puppet-os-hardening/issues/284) 20 | - Backwards incompatible breaking change in PR279 \(\#284\) [\#285](https://github.com/dev-sec/puppet-os-hardening/pull/285) ([earthgecko](https://github.com/earthgecko)) 21 | 22 | ## [v2.3.2](https://github.com/dev-sec/puppet-os-hardening/tree/v2.3.2) (2021-07-22) 23 | 24 | [Full Changelog](https://github.com/dev-sec/puppet-os-hardening/compare/2.3.1...v2.3.2) 25 | 26 | **Implemented enhancements:** 27 | 28 | - Add Puppet 7 tests + new versions [\#282](https://github.com/dev-sec/puppet-os-hardening/pull/282) ([mcgege](https://github.com/mcgege)) 29 | - Remove Puppet v5 support + tests [\#281](https://github.com/dev-sec/puppet-os-hardening/pull/281) ([mcgege](https://github.com/mcgege)) 30 | - update to PDK template 2.1.1 [\#278](https://github.com/dev-sec/puppet-os-hardening/pull/278) ([mcgege](https://github.com/mcgege)) 31 | - Add documentation on hiera usage \(see \#248\) [\#274](https://github.com/dev-sec/puppet-os-hardening/pull/274) ([mcgege](https://github.com/mcgege)) 32 | - Update to PDK 2.0 template [\#273](https://github.com/dev-sec/puppet-os-hardening/pull/273) ([mcgege](https://github.com/mcgege)) 33 | - Fix: Dead links result in an error \#271 [\#272](https://github.com/dev-sec/puppet-os-hardening/pull/272) ([LooOOooM](https://github.com/LooOOooM)) 34 | - move to github actions [\#264](https://github.com/dev-sec/puppet-os-hardening/pull/264) ([schurzi](https://github.com/schurzi)) 35 | - fixed alignment of properties and indentation [\#263](https://github.com/dev-sec/puppet-os-hardening/pull/263) ([hp197](https://github.com/hp197)) 36 | - Added manage\_system\_users option and formatted properties [\#262](https://github.com/dev-sec/puppet-os-hardening/pull/262) ([hp197](https://github.com/hp197)) 37 | - use new syntax for stub in rspec [\#259](https://github.com/dev-sec/puppet-os-hardening/pull/259) ([schurzi](https://github.com/schurzi)) 38 | - Fix + switch for arp\_ignore [\#256](https://github.com/dev-sec/puppet-os-hardening/pull/256) ([mcgege](https://github.com/mcgege)) 39 | - Move from inspec to cinc [\#238](https://github.com/dev-sec/puppet-os-hardening/pull/238) ([mcgege](https://github.com/mcgege)) 40 | 41 | **Fixed bugs:** 42 | 43 | - Backwards incompatible breaking change in PR279 [\#284](https://github.com/dev-sec/puppet-os-hardening/issues/284) 44 | - Backwards incompatible breaking change in PR279 \(\#284\) [\#285](https://github.com/dev-sec/puppet-os-hardening/pull/285) ([earthgecko](https://github.com/earthgecko)) 45 | - Activate manage\_cron\_permissions to satisfy cron tests [\#269](https://github.com/dev-sec/puppet-os-hardening/pull/269) ([mcgege](https://github.com/mcgege)) 46 | - Solve bundle problem on automated tests [\#268](https://github.com/dev-sec/puppet-os-hardening/pull/268) ([mcgege](https://github.com/mcgege)) 47 | - add source for chef-utils gem \(bundle confusion\) [\#265](https://github.com/dev-sec/puppet-os-hardening/pull/265) ([mcgege](https://github.com/mcgege)) 48 | - Revert "secure\_redirects should be set to 1 \(default\)" [\#260](https://github.com/dev-sec/puppet-os-hardening/pull/260) ([mcgege](https://github.com/mcgege)) 49 | - Switch to Inspec 4 to break bundler loop [\#257](https://github.com/dev-sec/puppet-os-hardening/pull/257) ([mcgege](https://github.com/mcgege)) 50 | 51 | **Merged pull requests:** 52 | 53 | - Add ignore\_max\_files\_warnings \(\#279\) [\#280](https://github.com/dev-sec/puppet-os-hardening/pull/280) ([earthgecko](https://github.com/earthgecko)) 54 | - Disable sysctl configuration [\#253](https://github.com/dev-sec/puppet-os-hardening/pull/253) ([Tahitibob35](https://github.com/Tahitibob35)) 55 | 56 | ## [2.3.1](https://github.com/dev-sec/puppet-os-hardening/tree/2.3.1) (2021-07-19) 57 | 58 | [Full Changelog](https://github.com/dev-sec/puppet-os-hardening/compare/2.3.0...2.3.1) 59 | 60 | **Implemented enhancements:** 61 | 62 | - Add support for Puppet 7 [\#267](https://github.com/dev-sec/puppet-os-hardening/issues/267) 63 | - allow defining parameters in hiera [\#248](https://github.com/dev-sec/puppet-os-hardening/issues/248) 64 | - Add integration tests for current platforms [\#172](https://github.com/dev-sec/puppet-os-hardening/issues/172) 65 | 66 | **Closed issues:** 67 | 68 | - New warning - max\_files - exceeds the default soft limit 1000 [\#279](https://github.com/dev-sec/puppet-os-hardening/issues/279) 69 | - enable\_log\_martians to false are logged [\#277](https://github.com/dev-sec/puppet-os-hardening/issues/277) 70 | - Dead links result in an error [\#271](https://github.com/dev-sec/puppet-os-hardening/issues/271) 71 | - Duplicate declaration [\#270](https://github.com/dev-sec/puppet-os-hardening/issues/270) 72 | - Using relative file modes can result very wrong in some cases [\#222](https://github.com/dev-sec/puppet-os-hardening/issues/222) 73 | 74 | ## [2.3.0](https://github.com/dev-sec/puppet-os-hardening/tree/2.3.0) (2021-02-10) 75 | 76 | [Full Changelog](https://github.com/dev-sec/puppet-os-hardening/compare/2.2.11...2.3.0) 77 | 78 | **Implemented enhancements:** 79 | 80 | - Use CINC \(instead of InSpec 4\) [\#212](https://github.com/dev-sec/puppet-os-hardening/issues/212) 81 | 82 | **Fixed bugs:** 83 | 84 | - Fix Travis tests [\#255](https://github.com/dev-sec/puppet-os-hardening/issues/255) 85 | 86 | **Closed issues:** 87 | 88 | - Fix broken tests in Travis CI [\#123](https://github.com/dev-sec/puppet-os-hardening/issues/123) 89 | 90 | ## [2.2.11](https://github.com/dev-sec/puppet-os-hardening/tree/2.2.11) (2021-01-27) 91 | 92 | [Full Changelog](https://github.com/dev-sec/puppet-os-hardening/compare/2.2.10...2.2.11) 93 | 94 | **Closed issues:** 95 | 96 | - Default $arp\_restricted=true breaks Calico overlay network [\#254](https://github.com/dev-sec/puppet-os-hardening/issues/254) 97 | 98 | ## [2.2.10](https://github.com/dev-sec/puppet-os-hardening/tree/2.2.10) (2020-12-28) 99 | 100 | [Full Changelog](https://github.com/dev-sec/puppet-os-hardening/compare/2.2.9...2.2.10) 101 | 102 | **Closed issues:** 103 | 104 | - os\_hardening failing on centos7 [\#241](https://github.com/dev-sec/puppet-os-hardening/issues/241) 105 | 106 | ## [2.2.9](https://github.com/dev-sec/puppet-os-hardening/tree/2.2.9) (2020-12-03) 107 | 108 | [Full Changelog](https://github.com/dev-sec/puppet-os-hardening/compare/2.2.8...2.2.9) 109 | 110 | **Implemented enhancements:** 111 | 112 | - More secure kernel settings [\#250](https://github.com/dev-sec/puppet-os-hardening/pull/250) ([mcgege](https://github.com/mcgege)) 113 | - Set SHA\_CRYPT\_\*\_ROUNDS \(Telekom security req linux-10\) [\#249](https://github.com/dev-sec/puppet-os-hardening/pull/249) ([mcgege](https://github.com/mcgege)) 114 | - Update to PDK 1.18.1 [\#242](https://github.com/dev-sec/puppet-os-hardening/pull/242) ([mcgege](https://github.com/mcgege)) 115 | - Updates from pdk template 1.17.0 [\#236](https://github.com/dev-sec/puppet-os-hardening/pull/236) ([mcgege](https://github.com/mcgege)) 116 | - If disabled service should also be stopped [\#226](https://github.com/dev-sec/puppet-os-hardening/pull/226) ([mcgege](https://github.com/mcgege)) 117 | - Manage files /etc/anacrontab and crontab equally [\#225](https://github.com/dev-sec/puppet-os-hardening/pull/225) ([mcgege](https://github.com/mcgege)) 118 | - Proxy support / SUSE fixes [\#217](https://github.com/dev-sec/puppet-os-hardening/pull/217) ([mcgege](https://github.com/mcgege)) 119 | - Updates from pdk template 1.11.1 [\#215](https://github.com/dev-sec/puppet-os-hardening/pull/215) ([mcgege](https://github.com/mcgege)) 120 | - Metadata / Travis fixes [\#211](https://github.com/dev-sec/puppet-os-hardening/pull/211) ([mcgege](https://github.com/mcgege)) 121 | - CIS: Fix permissions on home cron and log dirs [\#203](https://github.com/dev-sec/puppet-os-hardening/pull/203) ([PenguinFreeDom](https://github.com/PenguinFreeDom)) 122 | - Adjust .travis.yml to PDK template [\#197](https://github.com/dev-sec/puppet-os-hardening/pull/197) ([mcgege](https://github.com/mcgege)) 123 | - Integration tests with DigitalOcean \(see \#180\) [\#194](https://github.com/dev-sec/puppet-os-hardening/pull/194) ([mcgege](https://github.com/mcgege)) 124 | - Update to PDK 1.9.1 [\#191](https://github.com/dev-sec/puppet-os-hardening/pull/191) ([mcgege](https://github.com/mcgege)) 125 | - Update to PDK 1.9.0 [\#190](https://github.com/dev-sec/puppet-os-hardening/pull/190) ([mcgege](https://github.com/mcgege)) 126 | - Readme updates [\#188](https://github.com/dev-sec/puppet-os-hardening/pull/188) ([mcgege](https://github.com/mcgege)) 127 | - Replace sysctl module [\#183](https://github.com/dev-sec/puppet-os-hardening/pull/183) ([mcgege](https://github.com/mcgege)) 128 | - Add version tag on puppetforge [\#182](https://github.com/dev-sec/puppet-os-hardening/pull/182) ([mcgege](https://github.com/mcgege)) 129 | - New option rpfilter\_loose to enable loose mode \(rp\_filter = 2\) [\#163](https://github.com/dev-sec/puppet-os-hardening/pull/163) ([mcgege](https://github.com/mcgege)) 130 | - Easy add and remove packages, disable services [\#138](https://github.com/dev-sec/puppet-os-hardening/pull/138) ([timstoop](https://github.com/timstoop)) 131 | 132 | **Fixed bugs:** 133 | 134 | - Fix for integration tests \(apt-transport-https missing\) [\#237](https://github.com/dev-sec/puppet-os-hardening/pull/237) ([mcgege](https://github.com/mcgege)) 135 | - Travis-CI fix \(kitchen / faraday broken?\) [\#228](https://github.com/dev-sec/puppet-os-hardening/pull/228) ([mcgege](https://github.com/mcgege)) 136 | - Augeas sysctl needs explicit string value [\#207](https://github.com/dev-sec/puppet-os-hardening/pull/207) ([mcgege](https://github.com/mcgege)) 137 | - Add dirs to exclude to .pdkignore [\#196](https://github.com/dev-sec/puppet-os-hardening/pull/196) ([mcgege](https://github.com/mcgege)) 138 | - Add missing dependency [\#184](https://github.com/dev-sec/puppet-os-hardening/pull/184) ([theosotr](https://github.com/theosotr)) 139 | 140 | **Merged pull requests:** 141 | 142 | - Adapt Travis to puppetlabs standard [\#247](https://github.com/dev-sec/puppet-os-hardening/pull/247) ([mcgege](https://github.com/mcgege)) 143 | - Small fixes [\#243](https://github.com/dev-sec/puppet-os-hardening/pull/243) ([mcgege](https://github.com/mcgege)) 144 | - patch-cumuluslinux-support [\#239](https://github.com/dev-sec/puppet-os-hardening/pull/239) ([mdklapwijk](https://github.com/mdklapwijk)) 145 | - Update to PDK 1.15 [\#233](https://github.com/dev-sec/puppet-os-hardening/pull/233) ([mcgege](https://github.com/mcgege)) 146 | - Small fix on kitchen.yml [\#232](https://github.com/dev-sec/puppet-os-hardening/pull/232) ([mcgege](https://github.com/mcgege)) 147 | - CentOS 8 support [\#229](https://github.com/dev-sec/puppet-os-hardening/pull/229) ([mcgege](https://github.com/mcgege)) 148 | - Updates from pdk template 1.13.0 [\#227](https://github.com/dev-sec/puppet-os-hardening/pull/227) ([mcgege](https://github.com/mcgege)) 149 | - Updates from pdk template 1.12.0 [\#221](https://github.com/dev-sec/puppet-os-hardening/pull/221) ([mcgege](https://github.com/mcgege)) 150 | - allow puppet-stdlib v6 [\#219](https://github.com/dev-sec/puppet-os-hardening/pull/219) ([mcgege](https://github.com/mcgege)) 151 | - OpenSUSE 42.3 docker image correction [\#214](https://github.com/dev-sec/puppet-os-hardening/pull/214) ([mcgege](https://github.com/mcgege)) 152 | - Kitchen fix [\#206](https://github.com/dev-sec/puppet-os-hardening/pull/206) ([mcgege](https://github.com/mcgege)) 153 | - Some applications require different setting for icmp\_ratelimit [\#204](https://github.com/dev-sec/puppet-os-hardening/pull/204) ([tuxmea](https://github.com/tuxmea)) 154 | - Update to PDK 1.10.0 [\#193](https://github.com/dev-sec/puppet-os-hardening/pull/193) ([mcgege](https://github.com/mcgege)) 155 | - Replace Gitter with mailing lists [\#185](https://github.com/dev-sec/puppet-os-hardening/pull/185) ([mcgege](https://github.com/mcgege)) 156 | - Bugfix script to change file + dir permissions for Puppet Forge build [\#176](https://github.com/dev-sec/puppet-os-hardening/pull/176) ([mcgege](https://github.com/mcgege)) 157 | - Also works with current puppetlabs/stdlib \(5.1.0 tested\) [\#168](https://github.com/dev-sec/puppet-os-hardening/pull/168) ([mcgege](https://github.com/mcgege)) 158 | - Do not disable vfat. Fixes \#165. [\#166](https://github.com/dev-sec/puppet-os-hardening/pull/166) ([timstoop](https://github.com/timstoop)) 159 | - Add support for Ubuntu 18.04 and SLES 15 in metadata.json [\#162](https://github.com/dev-sec/puppet-os-hardening/pull/162) ([mcgege](https://github.com/mcgege)) 160 | - Update issue templates [\#158](https://github.com/dev-sec/puppet-os-hardening/pull/158) ([rndmh3ro](https://github.com/rndmh3ro)) 161 | - rework README [\#155](https://github.com/dev-sec/puppet-os-hardening/pull/155) ([mcgege](https://github.com/mcgege)) 162 | - Create license file [\#154](https://github.com/dev-sec/puppet-os-hardening/pull/154) ([mcgege](https://github.com/mcgege)) 163 | - Create license file [\#153](https://github.com/dev-sec/puppet-os-hardening/pull/153) ([mcgege](https://github.com/mcgege)) 164 | - Add 'MANAGED BY PUPPET' header [\#150](https://github.com/dev-sec/puppet-os-hardening/pull/150) ([hdep](https://github.com/hdep)) 165 | - Fix missing Requirements in Readme [\#149](https://github.com/dev-sec/puppet-os-hardening/pull/149) ([hdep](https://github.com/hdep)) 166 | - Add OpenSUSE 15 to the supported distributions [\#148](https://github.com/dev-sec/puppet-os-hardening/pull/148) ([mcgege](https://github.com/mcgege)) 167 | 168 | ## [2.2.8](https://github.com/dev-sec/puppet-os-hardening/tree/2.2.8) (2020-06-01) 169 | 170 | [Full Changelog](https://github.com/dev-sec/puppet-os-hardening/compare/2.2.7...2.2.8) 171 | 172 | **Fixed bugs:** 173 | 174 | - Minimize\_access to File \[/usr/bin\] issue [\#234](https://github.com/dev-sec/puppet-os-hardening/issues/234) 175 | 176 | **Closed issues:** 177 | 178 | - Conflicts with apache module [\#231](https://github.com/dev-sec/puppet-os-hardening/issues/231) 179 | 180 | ## [2.2.7](https://github.com/dev-sec/puppet-os-hardening/tree/2.2.7) (2019-10-04) 181 | 182 | [Full Changelog](https://github.com/dev-sec/puppet-os-hardening/compare/2.2.6...2.2.7) 183 | 184 | **Closed issues:** 185 | 186 | - disabled\_services should be stopped too [\#224](https://github.com/dev-sec/puppet-os-hardening/issues/224) 187 | - os\_hardening::minimize\_access should treat anacrontab the same as crontab [\#223](https://github.com/dev-sec/puppet-os-hardening/issues/223) 188 | 189 | ## [2.2.6](https://github.com/dev-sec/puppet-os-hardening/tree/2.2.6) (2019-07-24) 190 | 191 | [Full Changelog](https://github.com/dev-sec/puppet-os-hardening/compare/2.2.5...2.2.6) 192 | 193 | **Fixed bugs:** 194 | 195 | - Approve stdlib v6 + resolve librarian-puppet problem [\#213](https://github.com/dev-sec/puppet-os-hardening/issues/213) 196 | 197 | **Closed issues:** 198 | 199 | - Error: no implicit conversion of Integer into String [\#199](https://github.com/dev-sec/puppet-os-hardening/issues/199) 200 | 201 | ## [2.2.5](https://github.com/dev-sec/puppet-os-hardening/tree/2.2.5) (2019-06-01) 202 | 203 | [Full Changelog](https://github.com/dev-sec/puppet-os-hardening/compare/2.2.4...2.2.5) 204 | 205 | ## [2.2.4](https://github.com/dev-sec/puppet-os-hardening/tree/2.2.4) (2019-05-01) 206 | 207 | [Full Changelog](https://github.com/dev-sec/puppet-os-hardening/compare/2.2.3...2.2.4) 208 | 209 | ## [2.2.3](https://github.com/dev-sec/puppet-os-hardening/tree/2.2.3) (2019-05-01) 210 | 211 | [Full Changelog](https://github.com/dev-sec/puppet-os-hardening/compare/2.2.2...2.2.3) 212 | 213 | ## [2.2.2](https://github.com/dev-sec/puppet-os-hardening/tree/2.2.2) (2019-02-28) 214 | 215 | [Full Changelog](https://github.com/dev-sec/puppet-os-hardening/compare/2.2.1...2.2.2) 216 | 217 | **Fixed bugs:** 218 | 219 | - Wrong permission on module files [\#175](https://github.com/dev-sec/puppet-os-hardening/issues/175) 220 | 221 | ## [2.2.1](https://github.com/dev-sec/puppet-os-hardening/tree/2.2.1) (2019-01-28) 222 | 223 | [Full Changelog](https://github.com/dev-sec/puppet-os-hardening/compare/2.2.0...2.2.1) 224 | 225 | ## [2.2.0](https://github.com/dev-sec/puppet-os-hardening/tree/2.2.0) (2019-01-27) 226 | 227 | [Full Changelog](https://github.com/dev-sec/puppet-os-hardening/compare/2.1.3...2.2.0) 228 | 229 | **Implemented enhancements:** 230 | 231 | - Test / Update for Puppet 6 [\#156](https://github.com/dev-sec/puppet-os-hardening/issues/156) 232 | - Convert module into "standardized PDK module" [\#107](https://github.com/dev-sec/puppet-os-hardening/issues/107) 233 | - Update to verify the module against https://github.com/dev-sec/linux-baseline [\#79](https://github.com/dev-sec/puppet-os-hardening/issues/79) 234 | - Update test mechanisms [\#169](https://github.com/dev-sec/puppet-os-hardening/pull/169) ([mcgege](https://github.com/mcgege)) 235 | - Support os umask [\#152](https://github.com/dev-sec/puppet-os-hardening/pull/152) ([hdep](https://github.com/hdep)) 236 | 237 | **Fixed bugs:** 238 | 239 | - Rhel 7 won't boot on physical server [\#165](https://github.com/dev-sec/puppet-os-hardening/issues/165) 240 | 241 | **Closed issues:** 242 | 243 | - Wrong permission on git project files ? [\#164](https://github.com/dev-sec/puppet-os-hardening/issues/164) 244 | - module on the forge is not in sync with version of github [\#160](https://github.com/dev-sec/puppet-os-hardening/issues/160) 245 | - Fix broken tests in Travis CI [\#123](https://github.com/dev-sec/puppet-os-hardening/issues/123) 246 | 247 | ## [2.1.3](https://github.com/dev-sec/puppet-os-hardening/tree/2.1.3) (2018-11-12) 248 | 249 | [Full Changelog](https://github.com/dev-sec/puppet-os-hardening/compare/2.1.2...2.1.3) 250 | 251 | **Closed issues:** 252 | 253 | - user resource conflict with puppetlabs/apache: Duplicate declaration: User\[www-data\] is already declared [\#157](https://github.com/dev-sec/puppet-os-hardening/issues/157) 254 | - Missing comments in managed file : file managed by puppet [\#146](https://github.com/dev-sec/puppet-os-hardening/issues/146) 255 | - Missing requirements in readme file [\#145](https://github.com/dev-sec/puppet-os-hardening/issues/145) 256 | 257 | ## [2.1.2](https://github.com/dev-sec/puppet-os-hardening/tree/2.1.2) (2018-08-15) 258 | 259 | [Full Changelog](https://github.com/dev-sec/puppet-os-hardening/compare/2.1.1...2.1.2) 260 | 261 | **Implemented enhancements:** 262 | 263 | - Deploy GRUB hardening [\#137](https://github.com/dev-sec/puppet-os-hardening/pull/137) ([timstoop](https://github.com/timstoop)) 264 | - Only allow root and members of group wheel to use su [\#134](https://github.com/dev-sec/puppet-os-hardening/pull/134) ([timstoop](https://github.com/timstoop)) 265 | - Fix permissions on /etc/gshadow, based on CIS DIL Benchmark 6.1.5. [\#133](https://github.com/dev-sec/puppet-os-hardening/pull/133) ([timstoop](https://github.com/timstoop)) 266 | 267 | **Merged pull requests:** 268 | 269 | - Add stricter file permissions + PE fix [\#136](https://github.com/dev-sec/puppet-os-hardening/pull/136) ([mcgege](https://github.com/mcgege)) 270 | 271 | ## [2.1.1](https://github.com/dev-sec/puppet-os-hardening/tree/2.1.1) (2018-05-17) 272 | 273 | [Full Changelog](https://github.com/dev-sec/puppet-os-hardening/compare/2.1.0...2.1.1) 274 | 275 | **Implemented enhancements:** 276 | 277 | - Adding new param to specify maildir path. Updated nologin path for Re… [\#127](https://github.com/dev-sec/puppet-os-hardening/pull/127) ([hundredacres](https://github.com/hundredacres)) 278 | - converted module to pdk \#107 [\#120](https://github.com/dev-sec/puppet-os-hardening/pull/120) ([enemarke](https://github.com/enemarke)) 279 | 280 | **Closed issues:** 281 | 282 | - net.ipv4.tcp\_rfc1337 not a valid sysctl key [\#124](https://github.com/dev-sec/puppet-os-hardening/issues/124) 283 | 284 | **Merged pull requests:** 285 | 286 | - Add password\_warn\_age parameter for login.defs [\#128](https://github.com/dev-sec/puppet-os-hardening/pull/128) ([claw-real](https://github.com/claw-real)) 287 | - CI: switch testing to DigitalOcean [\#126](https://github.com/dev-sec/puppet-os-hardening/pull/126) ([artem-sidorenko](https://github.com/artem-sidorenko)) 288 | - Refactoring and new spec test [\#121](https://github.com/dev-sec/puppet-os-hardening/pull/121) ([enemarke](https://github.com/enemarke)) 289 | 290 | ## [2.1.0](https://github.com/dev-sec/puppet-os-hardening/tree/2.1.0) (2018-01-17) 291 | 292 | [Full Changelog](https://github.com/dev-sec/puppet-os-hardening/compare/2.0.0...2.1.0) 293 | 294 | **Implemented enhancements:** 295 | 296 | - Use type checking by defining data types [\#114](https://github.com/dev-sec/puppet-os-hardening/pull/114) ([mcgege](https://github.com/mcgege)) 297 | - Make parameter USERGROUPS\_ENAB in login.defs configurable [\#113](https://github.com/dev-sec/puppet-os-hardening/pull/113) ([mcgege](https://github.com/mcgege)) 298 | 299 | **Fixed bugs:** 300 | 301 | - Limit recursive file/directory check [\#116](https://github.com/dev-sec/puppet-os-hardening/pull/116) ([mcgege](https://github.com/mcgege)) 302 | 303 | **Closed issues:** 304 | 305 | - Minimize access needs a better way of removing +w on system folders [\#60](https://github.com/dev-sec/puppet-os-hardening/issues/60) 306 | - login.defs for different OS [\#57](https://github.com/dev-sec/puppet-os-hardening/issues/57) 307 | - Adduser consistency [\#49](https://github.com/dev-sec/puppet-os-hardening/issues/49) 308 | - Cleanup headers / copyright [\#111](https://github.com/dev-sec/puppet-os-hardening/issues/111) 309 | - Update some RH settings in this module [\#102](https://github.com/dev-sec/puppet-os-hardening/issues/102) 310 | 311 | **Merged pull requests:** 312 | 313 | - Get CI tests running on azure [\#115](https://github.com/dev-sec/puppet-os-hardening/pull/115) ([artem-sidorenko](https://github.com/artem-sidorenko)) 314 | - Correct header comments in sysctl.pp [\#69](https://github.com/dev-sec/puppet-os-hardening/pull/69) ([Zordrak](https://github.com/Zordrak)) 315 | - Skip entropy tests and disable auditd tests [\#117](https://github.com/dev-sec/puppet-os-hardening/pull/117) ([artem-sidorenko](https://github.com/artem-sidorenko)) 316 | - Making test-kitchen work again [\#112](https://github.com/dev-sec/puppet-os-hardening/pull/112) ([artem-sidorenko](https://github.com/artem-sidorenko)) 317 | - Implement new RH defaults \(see issue \#102\) [\#103](https://github.com/dev-sec/puppet-os-hardening/pull/103) ([mcgege](https://github.com/mcgege)) 318 | 319 | ## [2.0.0](https://github.com/dev-sec/puppet-os-hardening/tree/2.0.0) (2017-12-19) 320 | 321 | [Full Changelog](https://github.com/dev-sec/puppet-os-hardening/compare/1.1.2...2.0.0) 322 | 323 | **Closed issues:** 324 | 325 | - SLES and OEL errors when ipv6 is disabled [\#82](https://github.com/dev-sec/puppet-os-hardening/issues/82) 326 | - Failed to generate additional resources [\#75](https://github.com/dev-sec/puppet-os-hardening/issues/75) 327 | - Multiple conflicts with Puppet Enterprise [\#74](https://github.com/dev-sec/puppet-os-hardening/issues/74) 328 | - Conflict with Puppet Enterprise 2016.1.1 [\#71](https://github.com/dev-sec/puppet-os-hardening/issues/71) 329 | - allow\_core\_dump set to true still ends up setting /etc/security/limits.d/10.hardcore.conf and /etc/profile.d/pinerolo\_profile.sh files [\#68](https://github.com/dev-sec/puppet-os-hardening/issues/68) 330 | - IPv6 setting problem [\#67](https://github.com/dev-sec/puppet-os-hardening/issues/67) 331 | - Log martian packets [\#66](https://github.com/dev-sec/puppet-os-hardening/issues/66) 332 | - Merge \#64 [\#65](https://github.com/dev-sec/puppet-os-hardening/issues/65) 333 | - net.ipv6.conf.default.accept\_ra [\#56](https://github.com/dev-sec/puppet-os-hardening/issues/56) 334 | - Publish new release on Puppet Forge [\#104](https://github.com/dev-sec/puppet-os-hardening/issues/104) 335 | 336 | **Merged pull requests:** 337 | 338 | - Update links + contributors in README [\#108](https://github.com/dev-sec/puppet-os-hardening/pull/108) ([mcgege](https://github.com/mcgege)) 339 | - Avoid picking up users retrieved from SSSD or other domain services. [\#101](https://github.com/dev-sec/puppet-os-hardening/pull/101) ([tprobinson](https://github.com/tprobinson)) 340 | - Implement linux-baseline os-10 [\#100](https://github.com/dev-sec/puppet-os-hardening/pull/100) ([mcgege](https://github.com/mcgege)) 341 | - Style Guide corrections [\#98](https://github.com/dev-sec/puppet-os-hardening/pull/98) ([mcgege](https://github.com/mcgege)) 342 | - Update module metadata [\#97](https://github.com/dev-sec/puppet-os-hardening/pull/97) ([mcgege](https://github.com/mcgege)) 343 | - Baseline sysctl-17: Enable logging of martian packets [\#96](https://github.com/dev-sec/puppet-os-hardening/pull/96) ([mcgege](https://github.com/mcgege)) 344 | - One single coredump parameter [\#95](https://github.com/dev-sec/puppet-os-hardening/pull/95) ([mcgege](https://github.com/mcgege)) 345 | - Fix for Linux Baseline os-02 [\#94](https://github.com/dev-sec/puppet-os-hardening/pull/94) ([mcgege](https://github.com/mcgege)) 346 | - Baseline os-05b: set SYS\_\[GU\]ID\_\[MIN|MAX\] in /etc/login.defs [\#92](https://github.com/dev-sec/puppet-os-hardening/pull/92) ([mcgege](https://github.com/mcgege)) 347 | - Remove config/scripts to prevent core dumps if function is disabled… [\#91](https://github.com/dev-sec/puppet-os-hardening/pull/91) ([mcgege](https://github.com/mcgege)) 348 | - DevSec Linux Baseline os-05 [\#90](https://github.com/dev-sec/puppet-os-hardening/pull/90) ([mcgege](https://github.com/mcgege)) 349 | - Corrected handling of /bin/su \(via allow\_change\_user\) [\#89](https://github.com/dev-sec/puppet-os-hardening/pull/89) ([mcgege](https://github.com/mcgege)) 350 | - Documentation update [\#88](https://github.com/dev-sec/puppet-os-hardening/pull/88) ([mcgege](https://github.com/mcgege)) 351 | - added switch manage\_ipv6, so people could disable managing of ipv6 co… [\#87](https://github.com/dev-sec/puppet-os-hardening/pull/87) ([STetzel](https://github.com/STetzel)) 352 | - CentOS7 issue - revert "Remove link following in minimize\_access file resource" [\#86](https://github.com/dev-sec/puppet-os-hardening/pull/86) ([mcgege](https://github.com/mcgege)) 353 | - Making rubocop happy [\#85](https://github.com/dev-sec/puppet-os-hardening/pull/85) ([artem-sidorenko](https://github.com/artem-sidorenko)) 354 | - Make the sysctl setting 'rp\_filter' configurable [\#84](https://github.com/dev-sec/puppet-os-hardening/pull/84) ([mcgege](https://github.com/mcgege)) 355 | - Quick fix for issue \#71: remove '/usr/local/bin' from managed folders [\#83](https://github.com/dev-sec/puppet-os-hardening/pull/83) ([mcgege](https://github.com/mcgege)) 356 | - Puppet-lint done for sysctl.pp [\#81](https://github.com/dev-sec/puppet-os-hardening/pull/81) ([bitvijays](https://github.com/bitvijays)) 357 | - Fix the CI [\#80](https://github.com/dev-sec/puppet-os-hardening/pull/80) ([artem-sidorenko](https://github.com/artem-sidorenko)) 358 | - Adopt Puppet style guide - remove dynamic variable lookup [\#70](https://github.com/dev-sec/puppet-os-hardening/pull/70) ([tuxmea](https://github.com/tuxmea)) 359 | - Remove link following in minimize\_access file resource [\#64](https://github.com/dev-sec/puppet-os-hardening/pull/64) ([rooprob](https://github.com/rooprob)) 360 | - update common kitchen.yml platforms [\#63](https://github.com/dev-sec/puppet-os-hardening/pull/63) ([chris-rock](https://github.com/chris-rock)) 361 | - add support for limiting password reuse. [\#61](https://github.com/dev-sec/puppet-os-hardening/pull/61) ([igoraj](https://github.com/igoraj)) 362 | - add local testing section to readme [\#59](https://github.com/dev-sec/puppet-os-hardening/pull/59) ([chris-rock](https://github.com/chris-rock)) 363 | - add net.ipv6.conf.default.accept\_ra. closes \#56 [\#58](https://github.com/dev-sec/puppet-os-hardening/pull/58) ([igoraj](https://github.com/igoraj)) 364 | - Disable System Accounts [\#54](https://github.com/dev-sec/puppet-os-hardening/pull/54) ([igoraj](https://github.com/igoraj)) 365 | - common files: add centos 7 [\#53](https://github.com/dev-sec/puppet-os-hardening/pull/53) ([arlimus](https://github.com/arlimus)) 366 | - Prepare module for v2.0.0 [\#109](https://github.com/dev-sec/puppet-os-hardening/pull/109) ([mcgege](https://github.com/mcgege)) 367 | 368 | ## [1.1.2](https://github.com/dev-sec/puppet-os-hardening/tree/1.1.2) (2015-05-09) 369 | 370 | [Full Changelog](https://github.com/dev-sec/puppet-os-hardening/compare/1.1.1...1.1.2) 371 | 372 | **Merged pull requests:** 373 | 374 | - Update common readme badges + contributors + rubocop [\#52](https://github.com/dev-sec/puppet-os-hardening/pull/52) ([arlimus](https://github.com/arlimus)) 375 | - update common travis.yml, kitchen.yml platforms [\#51](https://github.com/dev-sec/puppet-os-hardening/pull/51) ([arlimus](https://github.com/arlimus)) 376 | - bugfix: use scoped resource for puppet 4 [\#50](https://github.com/dev-sec/puppet-os-hardening/pull/50) ([arlimus](https://github.com/arlimus)) 377 | 378 | # OLD Changelog 379 | 380 | ## 1.1.2 381 | 382 | * bugfix: ruby1.8+puppet+rspec interplay 383 | * bugfix: use scoped resource for puppet 4 384 | 385 | ## 1.1.1 386 | 387 | * feature: add stack protection configuration via sysctl (enabled) 388 | * bugfix: replace non-ascii char in login.defs 389 | * bugfix: follow links for RHEL7 /bin and /sbin 390 | * bugfix: fixed tty newlines 391 | * bugfix: minor log typos 392 | 393 | ## 1.1.0 394 | 395 | **API-change**: renamed module to `hardening-os_hardening` 396 | 397 | * improvement: linting 398 | 399 | ## 1.0.2 400 | 401 | * improvement: only run 'update-pam' when needed 402 | 403 | ## 1.0.1 404 | 405 | * bugfix: add missing colon for user-defined paths in PATH env 406 | * adjust login.defs template to not log user logins (as per Debian defaults) 407 | 408 | ## 1.0.0 409 | 410 | * add verified support for puppet 3.6, remove support for puppet 3.0 and 3.4 411 | * improvement: streamlined rubocop and puppet-lint 412 | * improvement: remove stdlib fixed version dependency 413 | * improvement: loosened thias/sysctl dependency 414 | * bugfix: get puppet version in gemfile from ENV: `PUPPET_VERSION` 415 | 416 | ## 0.1.3 417 | 418 | **API-change**: `dry_run_on_unkown` is now `dry_run_on_unknown` 419 | 420 | * feature: allow configuration of custom modules (if module loading is disabled) 421 | * improvement: only remove SUID/SGID if necessary 422 | * improvement: clarify SUID/SGID options 423 | * improvement: use thias/sysctl to configure sysctls (also fixes previous bugs with the template) 424 | * improvement: add spec tests for sysctl options 425 | * improvement: puppet-lint everything 426 | * improvement: add travis testing for lint+specs 427 | * improvement: use file resource instead of exec for access minimization 428 | * bugfix: fix typo dry_run_on_unkown -> dry_run_on_unknown 429 | * bugfix: don't run update initramfs on each run, only when required 430 | * bugfix: deactivation of kernel module loading wasn't implemented 431 | * bugfix: ip_forwarding wasn't activated correctly 432 | 433 | ## 0.1.2 434 | 435 | * feature: add additional ipv6 hardening to sysctl 436 | * feature: add test kitchen 437 | * improvement: remove unnecessary attributes from os_hardening::pam 438 | * bugfix: remove cracklib if passwdqc is used 439 | 440 | ## 0.1.1 441 | 442 | * feature: add configurable system environment 443 | * feature: remove suid/sgid bits from blacklist 444 | * feature: remove suid/sgid bits from unknown files 445 | 446 | ## 0.1.0 447 | 448 | * port from chef-os-hardening and monolithic puppet implementation 449 | 450 | 451 | \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* 452 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source ENV['GEM_SOURCE'] || 'https://rubygems.org' 2 | 3 | def location_for(place_or_version, fake_version = nil) 4 | git_url_regex = %r{\A(?(https?|git)[:@][^#]*)(#(?.*))?} 5 | file_url_regex = %r{\Afile:\/\/(?.*)} 6 | 7 | if place_or_version && (git_url = place_or_version.match(git_url_regex)) 8 | [fake_version, { git: git_url[:url], branch: git_url[:branch], require: false }].compact 9 | elsif place_or_version && (file_url = place_or_version.match(file_url_regex)) 10 | ['>= 0', { path: File.expand_path(file_url[:path]), require: false }] 11 | else 12 | [place_or_version, { require: false }] 13 | end 14 | end 15 | 16 | ruby_version_segments = Gem::Version.new(RUBY_VERSION.dup).segments 17 | minor_version = ruby_version_segments[0..1].join('.') 18 | 19 | group :development do 20 | gem "json", '= 2.7.2', require: false if Gem::Requirement.create('~> 2.4.2').satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 21 | gem "json", '= 2.7.2', require: false if Gem::Requirement.create(['>= 2.5.0', '< 2.7.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 22 | gem "json", '= 2.7.2', require: false if Gem::Requirement.create(['>= 2.7.0', '< 2.8.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 23 | gem "puppet-module-posix-default-r#{minor_version}", '~> 1.0', require: false, platforms: [:ruby] 24 | gem "puppet-module-posix-dev-r#{minor_version}", '~> 1.0', require: false, platforms: [:ruby] 25 | gem "puppet-module-win-default-r#{minor_version}", '~> 1.0', require: false, platforms: [:mswin, :mingw, :x64_mingw] 26 | gem "puppet-module-win-dev-r#{minor_version}", '~> 1.0', require: false, platforms: [:mswin, :mingw, :x64_mingw] 27 | gem "github_changelog_generator", require: false if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.3.0') 28 | end 29 | group :system_tests do 30 | gem "puppet-module-posix-system-r#{minor_version}", '~> 1.0', require: false, platforms: [:ruby] 31 | gem "puppet-module-win-system-r#{minor_version}", '~> 1.0', require: false, platforms: [:mswin, :mingw, :x64_mingw] 32 | end 33 | group :integration do 34 | gem "librarian-puppet", require: false 35 | gem "test-kitchen", require: false 36 | gem "kitchen-digitalocean", require: false 37 | gem "kitchen-docker", require: false, git: 'https://github.com/test-kitchen/kitchen-docker' 38 | gem "kitchen-inspec", require: false 39 | gem "kitchen-puppet", require: false 40 | gem "kitchen-sync", require: false 41 | gem "inspec", require: false, source: "https://rubygems.cinc.sh" 42 | gem "inspec-core", require: false, source: "https://rubygems.cinc.sh" 43 | gem "chef-utils", require: false, source: "https://rubygems.org/" 44 | gem "chef-config", require: false, source: "https://rubygems.org/" 45 | gem "unf_ext", require: false, source: "https://rubygems.org/" 46 | gem "sync", require: false, source: "https://rubygems.org/" 47 | end 48 | 49 | puppet_version = ENV['PUPPET_GEM_VERSION'] 50 | facter_version = ENV['FACTER_GEM_VERSION'] 51 | hiera_version = ENV['HIERA_GEM_VERSION'] 52 | 53 | gems = {} 54 | 55 | gems['puppet'] = location_for(puppet_version) 56 | 57 | # If facter or hiera versions have been specified via the environment 58 | # variables 59 | 60 | gems['facter'] = location_for(facter_version) if facter_version 61 | gems['hiera'] = location_for(hiera_version) if hiera_version 62 | 63 | gems.each do |gem_name, gem_params| 64 | gem gem_name, *gem_params 65 | end 66 | 67 | # Evaluate Gemfile.local and ~/.gemfile if they exist 68 | extra_gemfiles = [ 69 | "#{__FILE__}.local", 70 | File.join(Dir.home, '.gemfile'), 71 | ] 72 | 73 | extra_gemfiles.each do |gemfile| 74 | if File.file?(gemfile) && File.readable?(gemfile) 75 | eval(File.read(gemfile), binding) 76 | end 77 | end 78 | # vim: syntax=ruby 79 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | # OLD Changelog 2 | 3 | ## 1.1.2 4 | 5 | * bugfix: ruby1.8+puppet+rspec interplay 6 | * bugfix: use scoped resource for puppet 4 7 | 8 | ## 1.1.1 9 | 10 | * feature: add stack protection configuration via sysctl (enabled) 11 | * bugfix: replace non-ascii char in login.defs 12 | * bugfix: follow links for RHEL7 /bin and /sbin 13 | * bugfix: fixed tty newlines 14 | * bugfix: minor log typos 15 | 16 | ## 1.1.0 17 | 18 | **API-change**: renamed module to `hardening-os_hardening` 19 | 20 | * improvement: linting 21 | 22 | ## 1.0.2 23 | 24 | * improvement: only run 'update-pam' when needed 25 | 26 | ## 1.0.1 27 | 28 | * bugfix: add missing colon for user-defined paths in PATH env 29 | * adjust login.defs template to not log user logins (as per Debian defaults) 30 | 31 | ## 1.0.0 32 | 33 | * add verified support for puppet 3.6, remove support for puppet 3.0 and 3.4 34 | * improvement: streamlined rubocop and puppet-lint 35 | * improvement: remove stdlib fixed version dependency 36 | * improvement: loosened thias/sysctl dependency 37 | * bugfix: get puppet version in gemfile from ENV: `PUPPET_VERSION` 38 | 39 | ## 0.1.3 40 | 41 | **API-change**: `dry_run_on_unkown` is now `dry_run_on_unknown` 42 | 43 | * feature: allow configuration of custom modules (if module loading is disabled) 44 | * improvement: only remove SUID/SGID if necessary 45 | * improvement: clarify SUID/SGID options 46 | * improvement: use thias/sysctl to configure sysctls (also fixes previous bugs with the template) 47 | * improvement: add spec tests for sysctl options 48 | * improvement: puppet-lint everything 49 | * improvement: add travis testing for lint+specs 50 | * improvement: use file resource instead of exec for access minimization 51 | * bugfix: fix typo dry_run_on_unkown -> dry_run_on_unknown 52 | * bugfix: don't run update initramfs on each run, only when required 53 | * bugfix: deactivation of kernel module loading wasn't implemented 54 | * bugfix: ip_forwarding wasn't activated correctly 55 | 56 | ## 0.1.2 57 | 58 | * feature: add additional ipv6 hardening to sysctl 59 | * feature: add test kitchen 60 | * improvement: remove unnecessary attributes from os_hardening::pam 61 | * bugfix: remove cracklib if passwdqc is used 62 | 63 | ## 0.1.1 64 | 65 | * feature: add configurable system environment 66 | * feature: remove suid/sgid bits from blacklist 67 | * feature: remove suid/sgid bits from unknown files 68 | 69 | ## 0.1.0 70 | 71 | * port from chef-os-hardening and monolithic puppet implementation 72 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Puppet OS hardening 2 | 3 | [![Puppet Forge Version](https://img.shields.io/puppetforge/v/hardening/os_hardening.svg)][1] 4 | [![Puppet Forge Downloads](https://img.shields.io/puppetforge/dt/hardening/os_hardening.svg)][1] 5 | [![Puppet Forge Endorsement](https://img.shields.io/puppetforge/e/hardening/os_hardening.svg)][1] 6 | [![Build Status](https://github.com/dev-sec/puppet-os-hardening/workflows/tests/badge.svg)][2] 7 | 8 | #### Table of Contents 9 | 10 | 1. [Module Description - What the module does and why it is useful](#module-description) 11 | 1. [Setup - The basics of getting started with os_hardening](#setup) 12 | * [Setup Requirements](#setup-requirements) 13 | * [Beginning with os_hardening](#beginning-with-os_hardening) 14 | 1. [Usage - Configuration options and additional functionality](#usage) 15 | * [Important for Puppet Enterprise](#important-for-puppet-enterprise) 16 | * [Parameters](#parameters) 17 | * [Hiera usage](#hiera-usage) 18 | * [Note about wanted/unwanted packages and disabled services](#note-about-wantedunwanted-packages-and-disabled-services) 19 | 1. [Limitations - OS compatibility, etc.](#limitations) 20 | 1. [Development - Guide for contributing to the module](#development) 21 | 1. [Testing - Quality gates for your changes in the code](#testing) 22 | * [Local Testing](#local-testing) 23 | * [PDK Tests](#pdk-tests) 24 | * [Integration Tests (Docker)](#integration-tests-docker) 25 | * [Integration Tests (DigitalOcean)](#integration-tests-digitalocean) 26 | * [CI testing of PRs & forks](#ci-testing-of-prs--forks) 27 | 1. [Get in touch](#get-in-touch) 28 | 1. [Contributors + Kudos](#contributors--kudos) 29 | 1. [License and Author](#license-and-author) 30 | 31 | ## Module Description 32 | 33 | This Puppet module provides secure configuration of your base OS with hardening and is part of the [DevSec Hardening Framework](https://dev-sec.io). 34 | 35 | ## Setup 36 | 37 | ### Setup Requirements 38 | 39 | * Puppet OpenSource or Enterprise 40 | * [Module stdlib](https://forge.puppet.com/puppetlabs/stdlib) 41 | * [Module sysctl](https://forge.puppet.com/herculesteam/augeasproviders_sysctl) 42 | 43 | ### Beginning with os_hardening 44 | 45 | After adding this module, you can use the class: 46 | 47 | ```puppet 48 | class { 'os_hardening': } 49 | ``` 50 | 51 | All parameters are contained within the main `os_hardening` class, so you just have to pass them like this: 52 | 53 | ```puppet 54 | class { 'os_hardening': 55 | enable_ipv4_forwarding => true, 56 | } 57 | ``` 58 | 59 | ## Usage 60 | 61 | ### IMPORTANT for Puppet Enterprise 62 | 63 | **If you are using this module in a PE environment, you have to set** `pe_environment = true` 64 | Otherwise puppet will drop an error (duplicate resource)! 65 | 66 | ### Parameters 67 | 68 | * `system_environment = 'default'` 69 | define the context in which the system runs. Some options don't work for `docker`/`lxc` 70 | * `pe_environment = false` 71 | set this to true if you are using Puppet Enterprise **IMPORTANT - see above** 72 | * `extra_user_paths = []` 73 | add additional paths to the user's `PATH` variable (default is empty). 74 | * `umask = undef` 75 | umask used for the creation of new home directories by useradd / newusers (e.g. '027') 76 | * `maildir = undef` 77 | path for maildir (e.g. '/var/mail') 78 | * `usergroups = true` 79 | true if you want separate groups for each user, false otherwise 80 | * `sys_uid_min = undef` and `sys_gid_min = undef` 81 | override the default setting for `login.defs` 82 | * `password_max_age = 60` 83 | maximum password age 84 | * `password_min_age = 7` 85 | minimum password age (before allowing any other password change) 86 | * `password_warn_age = 7` 87 | Days warning before password change is due 88 | * `login_retries = 5` 89 | the maximum number of login retries if password is bad (normally overridden by PAM / auth_retries) 90 | * `login_timeout = 60` 91 | authentication timeout in seconds, so login will exit if this time passes 92 | * `chfn_restrict = ''` 93 | which fields may be changed by regular users using chfn 94 | * `allow_login_without_home = false` 95 | true if to allow users without home to login 96 | * `allow_change_user = false` 97 | if a user may use `su` to change his login 98 | * `ignore_users = []` 99 | array of system user accounts that should _not be_ hardened (password disabled and shell set to `/usr/sbin/nologin`) 100 | * `folders_to_restrict = ['/usr/local/games','/usr/local/sbin','/usr/local/bin','/usr/bin','/usr/sbin','/sbin','/bin']` 101 | folders to make sure of that group and world do not have write access to it or any of the contents 102 | * `ignore_max_files_warnings = false` 103 | true if you do not want puppet to log max_files and performance warnings on the recursion of folders with > 1000 files eg /bin /usr/bin 104 | * `recurselimit = 5` 105 | directory depth for recursive permission check 106 | * `passwdqc_enabled = true` 107 | true if you want to use strong password checking in PAM using passwdqc 108 | * `auth_retries = 5` 109 | the maximum number of authentication attempts, before the account is locked for some time 110 | * `auth_lockout_time = 600` 111 | time in seconds that needs to pass, if the account was locked due to too many failed authentication attempts 112 | * `passwdqc_options = 'min=disabled,disabled,16,12,8'` 113 | set to any option line (as a string) that you want to pass to passwdqc 114 | * `manage_pam_unix = false` 115 | true if you want pam_unix managed by this module 116 | * `enable_pw_history = true` 117 | true if you want pam_unix to remember password history to prevent reuse of passwords (requires `manage_pam_unix = true`) 118 | * `pw_remember_last = 5` 119 | the number of last passwords (e.g. 5 will prevent user to reuse any of her last 5 passwords) 120 | * `only_root_may_su = false` 121 | true when only root and member of the group wheel may use su, required to be true for CIS Benchmark compliance 122 | * `root_ttys = ['console','tty1','tty2','tty3','tty4','tty5','tty6']` 123 | registered TTYs for root 124 | * `whitelist = []` 125 | all files which should keep their SUID/SGID bits if set (will be combined with pre-defined whiteliste of files) 126 | * `blacklist = []` 127 | all files which should have their SUID/SGID bits removed if set (will be combined with pre-defined blacklist of files) 128 | * `remove_from_unknown = false` 129 | `true` if you want to remove SUID/SGID bits from any file, that is not explicitly configured in a `blacklist`. This will make every Puppet run search through the mounted filesystems looking for SUID/SGID bits that are not configured in the default and user blacklist. If it finds an SUID/SGID bit, it will be removed, unless this file is in your `whitelist`. 130 | * `dry_run_on_unknown = false` 131 | like `remove_from_unknown` above, only that SUID/SGID bits aren't removed. It will still search the filesystems to look for SUID/SGID bits but it will only print them in your log. This option is only ever recommended, when you first configure `remove_from_unknown` for SUID/SGID bits, so that you can see the files that are being changed and make adjustments to your `whitelist` and `blacklist`. 132 | * `enable_module_loading = true` 133 | true if you want to allowed to change kernel modules once the system is running (eg `modprobe`, `rmmod`) 134 | * `load_modules = []` 135 | load this modules via initramfs if enable_module_loading is false 136 | * `disable_filesystems = ['cramfs','freevxfs','jffs2','hfs','hfsplus','squashfs','udf']` 137 | array of filesystems (kernel modules) that should be disabled 138 | * `cpu_vendor = 'intel'` 139 | only required if `enable_module_loading = false`: set the CPU vendor for modules to load 140 | * `icmp_ratelimit = '100'` 141 | default value '100', allow overwriting, needs String 142 | * `desktop_enabled = false` 143 | true if this is a desktop system, ie Xorg, KDE/GNOME/Unity/etc 144 | * `enable_ipv4_forwarding = false` 145 | true if this system requires packet forwarding in IPv4 (eg Router), false otherwise 146 | * `manage_ipv6 = true` 147 | true to harden ipv6 setup, false to ignore ipv6 completely 148 | * `enable_ipv6 = false` 149 | false to disable ipv6 on this system, true to enable 150 | * `enable_ipv6_forwarding = false` 151 | true if this system requires packet forwarding in IPv6 (eg Router), false otherwise 152 | * `arp_restricted = true` 153 | true if you want the behavior of announcing and replying to ARP to be restricted, false otherwise 154 | * `arp_ignore_samenet = false` 155 | true will drop packets that are not from the same subnet (arp_ignore = 2), false will only check the target ip (arp_ignore = 1) 156 | * `enable_sysrq = false` 157 | true to enable the magic sysrq key, false otherwise 158 | * `enable_core_dump = false` 159 | false to prevent the creation of core dumps, true otherwise 160 | * `enable_stack_protection = true` 161 | for Address Space Layout Randomization. ASLR can help defeat certain types of buffer overflow attacks. ASLR can locate the base, libraries, heap, and stack at random positions in a process's address space, which makes it difficult for an attacking program to predict the memory address of the next instruction. 162 | * `enable_rpfilter = true` 163 | true to enable reverse path filtering (discard bogus packets), false otherwise 164 | * `rpfilter_loose = false` 165 | (only if `enable_rpfilter` is true) *loose mode* (rp_filter = 2) if true, *strict mode* otherwise 166 | * `enable_log_martians = true` 167 | true to enable logging on suspicious / unroutable network packets, false otherwise **WARNING - this might generate huge log files!** 168 | * `unwanted_packages = []` 169 | packages that should be removed from the system 170 | * `wanted_packages = []` 171 | packages that should be added to the system 172 | * `disabled_services = []` 173 | services that should not be enabled 174 | * `enable_grub_hardening = false` 175 | set to true to enable some grub hardening rules 176 | * `grub_user = 'root'` 177 | the grub username that needs to be provided when changing config on the grub prompt 178 | * `grub_password_hash = ''` 179 | a password hash created with `grub-mkpasswd-pbkdf2` that is associated with the grub\_user 180 | * `boot_without_password = true` 181 | setup Grub so it only requires a password when changing an entry, not when booting an existing entry 182 | * `system_umask = undef` 183 | if this variable is set setup the umask for all user in the system (e.g. '027') 184 | * `manage_home_permissions = false` 185 | set to true to manage local users file and directory permissions (g-w,o-rwx) 186 | * `ignore_home_users = []` 187 | array for users that is not to be restricted by manage_home_permissions 188 | * `manage_log_permissions = false` 189 | set to true to manage log file permissions (g-wx,o-rwx) 190 | * `restrict_log_dir = ['/var/log/']` 191 | set main log dir 192 | * `ignore_restrict_log_dir = []` 193 | array to exclude log dirs under the main log dir 194 | * `ignore_files_in_folder_to_restrict = []` 195 | array to ignore files to hardened in dirs under the folder_to_restrict array 196 | * `manage_cron_permissions = false` 197 | set to true to manage cron file permissions (og-rwx) 198 | * `enable_sysctl_config = true` 199 | set to false to disable sysctl configuration 200 | * `manage_system_users = true` 201 | set to false to disable managing of system users (empty password and setting nologin shell) 202 | * `shadow_group = undef` 203 | override the group ownership of /etc/shadow 204 | * `shadow_mode = undef` 205 | override the file permissions of /etc/shadow 206 | 207 | 208 | ### Hiera usage 209 | 210 | It's also possible to set the parameters in Hiera like this: 211 | 212 | ```puppet 213 | os_hardening::password_max_age: 90 214 | os_hardening::password_min_age: 0 215 | os_hardening::password_warn_age: 14 216 | os_hardening::unwanted_packages: ['telnet'] 217 | os_hardening::ignore_users: ['git','githook','ansible','apache','puppetboard'] 218 | ``` 219 | 220 | ### Note about wanted/unwanted packages and disabled services 221 | 222 | As the CIS Distribution Independent Linux Benchmark is a good starting point 223 | regarding hardening of systems, it was deemed appropriate to implement an easy 224 | way to deal with one-offs for which one doesn't want to write an entire module. 225 | 226 | For instance, to increase CIS DIL compliance on a Debian system, one should set 227 | the following: 228 | 229 | ```puppet 230 | wanted_packages => ['ntp'], 231 | unwanted_packages => ['telnet'], 232 | disabled_services => ['rsync'], 233 | ``` 234 | 235 | The default settings of NTP are actually pretty good for most situations, so it 236 | is not immediately necessary to implement a module. However, if you do use a 237 | module to control these services, that is of course preferred. 238 | 239 | ## Limitations 240 | 241 | This module has been tested and should run on most Linux distributions. For an extensive list of supported operating systems, see [metadata.json](https://github.com/dev-sec/puppet-os-hardening/blob/master/metadata.json) 242 | 243 | ## Development 244 | 245 | If you want to contribute, please follow our [contribution guide](https://dev-sec.io/contributing/). 246 | 247 | ## Testing 248 | 249 | ### Local Testing 250 | 251 | You should have Ruby interpreter installed on your system. It might be a good idea to use [rvm](https://rvm.io) for that purpose. Besides that you have to install the `Puppet Development Kit` [PDK](https://puppet.com/download-puppet-development-kit) and [Docker Community Edition](https://www.docker.com/products/docker-engine), as the integration tests run in Docker containers. 252 | 253 | For all our integration tests we use `test-kitchen`. If you are not familiar with `test-kitchen` please have a look at [their guide](http://kitchen.ci/docs/getting-started). 254 | 255 | #### PDK Tests 256 | 257 | ```bash 258 | # Syntax & Lint tests 259 | pdk validate 260 | 261 | # Unit Tests 262 | pdk test unit 263 | ``` 264 | 265 | #### Integration Tests (Docker) 266 | 267 | Per default the integration tests will run in docker containers - unfortunately not all tests can run in container environments (e.g. sysctl settings). 268 | 269 | ```bash 270 | # Install dependencies 271 | gem install bundler 272 | bundle install 273 | 274 | # list all test instances 275 | bundle exec kitchen list 276 | 277 | # fast test on one machine 278 | bundle exec kitchen test ubuntu-16-04-puppet5 279 | 280 | # test on all machines 281 | bundle exec kitchen test 282 | ``` 283 | 284 | #### Integration Tests (DigitalOcean) 285 | 286 | For complete integration tests with [DigitalOcean](https://cloud.digitalocean.com) you have to get an account there and setup some environment variables: 287 | 288 | * `KITCHEN_LOCAL_YAML=kitchen.do.yml` 289 | * `DIGITALOCEAN_ACCESS_TOKEN` - [access token for DigitalOcean](https://www.digitalocean.com/community/tutorials/how-to-use-the-digitalocean-api-v2) 290 | * `DIGITALOCEAN_SSH_KEY_IDS` - ID in DigitalOcean of your ssh key, see [this](https://github.com/test-kitchen/kitchen-digitalocean#installation-and-setup) for more information 291 | 292 | The ssh key has to be named `~/.ssh/do_ci` and added to your profile at DigitalOcean. 293 | After this you're ready to run the tests as described at [Integration Tests (Docker)](#integration-tests-docker). 294 | 295 | If you want to run the full integration tests with Github Actions in your fork, you will have to add these [environment variables](https://docs.github.com/en/actions/reference/encrypted-secrets) in the settings of your fork: 296 | 297 | * `KITCHEN_LOCAL_YAML=kitchen.do.yml` 298 | * `DIGITALOCEAN_ACCESS_TOKEN` - [access token for DigitalOcean](https://www.digitalocean.com/community/tutorials/how-to-use-the-digitalocean-api-v2) 299 | * `CI_SSH_KEY` - private part of a ssh key, available on DigitalOcean for your instances, in base64 encoded form (e.g. `cat id_rsa | base64 -w0 ; echo`) 300 | * `DIGITALOCEAN_SSH_KEY_IDS` - ID in DigitalOcean of `CI_SSH_KEY`, see [this](https://github.com/test-kitchen/kitchen-digitalocean#installation-and-setup) for more information 301 | 302 | ### CI testing of PRs & forks 303 | 304 | Your patches will automatically get tested via Github Actions. The test summary is visible on Github in your PR, details can be found in the linked tests. 305 | 306 | ## Get in touch 307 | 308 | You can reach us on several ways: 309 | 310 | * [@DevSecIO](https://twitter.com/DevSecIO) on Twitter 311 | * Mailing list for questions and general discussion: devsec@freelists.org [[subscribe]](https://www.freelists.org/list/devsec) 312 | * Mailing list with release announcements (no posts are possible here): devsec-announce@freelists.org [[subscribe]](https://www.freelists.org/list/devsec-announce) 313 | 314 | ## Contributors + Kudos 315 | 316 | * Dominik Richter [arlimus](https://github.com/arlimus) 317 | * Edmund Haselwanter [ehaselwanter](https://github.com/ehaselwanter) 318 | * Christoph Hartmann [chris-rock](https://github.com/chris-rock) 319 | * Thomas Dütsch [a-tom](https://github.com/a-tom) 320 | * Patrick Meier [atomic111](https://github.com/atomic111) 321 | * Artem Sidorenko [artem-sidorenko](https://github.com/artem-sidorenko) 322 | * Kurt Huwig [kurthuwig](https://github.com/kurthuwig) 323 | * Matthew Haughton [3flex](https://github.com/3flex) 324 | * Reik Keutterling [spielkind](https://github.com/spielkind) 325 | * Daniel Dreier [danieldreier](https://github.com/danieldreier) 326 | * Timo Goebel [timogoebel](https://github.com/timogoebel) 327 | * Tristan Helmich [fadenb](https://github.com/fadenb) 328 | * Michael Geiger [mcgege](https://github.com/mcgege) 329 | * Timo Bergemann [LooOOooM](https://github.com/LooOOooM) 330 | 331 | For the original port of `chef-os-hardening` to puppet: 332 | 333 | * Artem Sidorenko [artem-sidorenko](https://github.com/artem-sidorenko) 334 | * Frank Kloeker [eumel8](https://github.com/eumel8) 335 | 336 | Thank you all!! 337 | 338 | ## License and Author 339 | 340 | * Author:: Dominik Richter 341 | * Author:: Deutsche Telekom AG 342 | 343 | Licensed under the Apache License, Version 2.0 (the "License"); 344 | you may not use this file except in compliance with the License. 345 | You may obtain a copy of the License at 346 | 347 | ``` 348 | http://www.apache.org/licenses/LICENSE-2.0 349 | ``` 350 | 351 | Unless required by applicable law or agreed to in writing, software 352 | distributed under the License is distributed on an "AS IS" BASIS, 353 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 354 | See the License for the specific language governing permissions and 355 | limitations under the License. 356 | 357 | [1]: https://forge.puppet.com/hardening/os_hardening 358 | [2]: https://github.com/dev-sec/puppet-os-hardening/workflows/tests 359 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'bundler' 4 | require 'puppet_litmus/rake_tasks' if Bundler.rubygems.find_name('puppet_litmus').any? 5 | require 'puppetlabs_spec_helper/rake_tasks' 6 | require 'puppet-syntax/tasks/puppet-syntax' 7 | require 'puppet_blacksmith/rake_tasks' if Bundler.rubygems.find_name('puppet-blacksmith').any? 8 | require 'github_changelog_generator/task' if Bundler.rubygems.find_name('github_changelog_generator').any? 9 | require 'puppet-strings/tasks' if Bundler.rubygems.find_name('puppet-strings').any? 10 | 11 | import 'Rakefile.local' 12 | 13 | def changelog_user 14 | return unless Rake.application.top_level_tasks.include? "changelog" 15 | returnVal = "dev-sec" || JSON.load(File.read('metadata.json'))['author'] 16 | raise "unable to find the changelog_user in .sync.yml, or the author in metadata.json" if returnVal.nil? 17 | puts "GitHubChangelogGenerator user:#{returnVal}" 18 | returnVal 19 | end 20 | 21 | def changelog_project 22 | return unless Rake.application.top_level_tasks.include? "changelog" 23 | 24 | returnVal = "puppet-os-hardening" 25 | returnVal ||= begin 26 | metadata_source = JSON.load(File.read('metadata.json'))['source'] 27 | metadata_source_match = metadata_source && metadata_source.match(%r{.*\/([^\/]*?)(?:\.git)?\Z}) 28 | 29 | metadata_source_match && metadata_source_match[1] 30 | end 31 | 32 | raise "unable to find the changelog_project in .sync.yml or calculate it from the source in metadata.json" if returnVal.nil? 33 | 34 | puts "GitHubChangelogGenerator project:#{returnVal}" 35 | returnVal 36 | end 37 | 38 | def changelog_future_release 39 | return unless Rake.application.top_level_tasks.include? "changelog" 40 | returnVal = "v%s" % JSON.load(File.read('metadata.json'))['version'] 41 | raise "unable to find the future_release (version) in metadata.json" if returnVal.nil? 42 | puts "GitHubChangelogGenerator future_release:#{returnVal}" 43 | returnVal 44 | end 45 | 46 | PuppetLint.configuration.send('disable_relative') 47 | 48 | if Bundler.rubygems.find_name('github_changelog_generator').any? 49 | GitHubChangelogGenerator::RakeTask.new :changelog do |config| 50 | raise "Set CHANGELOG_GITHUB_TOKEN environment variable eg 'export CHANGELOG_GITHUB_TOKEN=valid_token_here'" if Rake.application.top_level_tasks.include? "changelog" and ENV['CHANGELOG_GITHUB_TOKEN'].nil? 51 | config.user = "#{changelog_user}" 52 | config.project = "#{changelog_project}" 53 | config.since_tag = "1.1.1" 54 | config.future_release = "#{changelog_future_release}" 55 | config.exclude_labels = ['no changelog','maintenance'] 56 | config.add_pr_wo_labels = true 57 | config.issues = true 58 | end 59 | else 60 | desc 'Generate a Changelog from GitHub' 61 | task :changelog do 62 | raise < 1.15' 71 | condition: "Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.3.0')" 72 | EOM 73 | end 74 | end 75 | 76 | -------------------------------------------------------------------------------- /Rakefile.local: -------------------------------------------------------------------------------- 1 | desc 'Run kitchen integration tests' 2 | task :kitchen do 3 | concurrency = ENV['CONCURRENCY'] || 1 4 | instance = ENV['INSTANCE'] || '' 5 | SSH_KEY_FILE = '~/.ssh/do_ci' 6 | SSH_KEY_ENV_VAR_NAME = 'CI_SSH_KEY' 7 | 8 | if ENV['CI'] && ENV['KITCHEN_LOCAL_YAML'] == 'kitchen.do.yml' 9 | puts 'Preparing CI environment for DigitalOcean...' 10 | 11 | ['DIGITALOCEAN_ACCESS_TOKEN', 'DIGITALOCEAN_SSH_KEY_IDS', SSH_KEY_ENV_VAR_NAME].each do |var| 12 | unless ENV[var] 13 | puts "#{var} isn't defined. Skipping the task" 14 | exit 15 | end 16 | end 17 | 18 | ssh_file = File.expand_path(SSH_KEY_FILE) 19 | dir = File.dirname(ssh_file) 20 | Dir.mkdir(dir, 0o700) unless Dir.exist?(dir) 21 | File.open(ssh_file, 'w') { |f| f.puts Base64.decode64(ENV[SSH_KEY_ENV_VAR_NAME]) } 22 | File.chmod(0o600, ssh_file) 23 | end 24 | 25 | sh('sh', '-c', "bundle exec kitchen test --destroy=always -c #{concurrency} #{instance}") 26 | end 27 | 28 | -------------------------------------------------------------------------------- /files/limits.conf: -------------------------------------------------------------------------------- 1 | # MANAGED BY PUPPET 2 | # Prevent core dumps for all users. These are usually only needed by developers and may contain sensitive information. 3 | * hard core 0 4 | -------------------------------------------------------------------------------- /files/profile.conf: -------------------------------------------------------------------------------- 1 | # MANAGED BY PUPPET 2 | # Disable core dumps via soft limits for all users. Compliance to this setting is voluntary and can be modified by users up to a hard limit. This setting is a sane default. 3 | ulimit -S -c 0 > /dev/null 2>&1 -------------------------------------------------------------------------------- /kitchen.do.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: digitalocean 4 | size: s-1vcpu-1gb 5 | region: nyc3 6 | 7 | provisioner: 8 | name: puppet_apply 9 | ignore_spec_fixtures: true 10 | manifests_path: test/fixtures/manifests.do 11 | modules_path: test/fixtures/modules 12 | puppetfile_path: test/fixtures/Puppetfile 13 | require_chef_for_busser: false 14 | 15 | platforms: 16 | - name: centos-7-puppet6 17 | provisioner: 18 | puppet_yum_repo: https://yum.puppetlabs.com/puppetlabs-release-el-7.noarch.rpm 19 | puppet_yum_collections_repo: http://yum.puppetlabs.com/puppet6/puppet6-release-el-7.noarch.rpm 20 | - name: centos-7-puppet7 21 | provisioner: 22 | puppet_yum_repo: https://yum.puppetlabs.com/puppetlabs-release-el-7.noarch.rpm 23 | puppet_yum_collections_repo: http://yum.puppetlabs.com/puppet7/puppet7-release-el-7.noarch.rpm 24 | - name: centos-8-puppet6 25 | driver_config: 26 | image: quay.io/centos/centos:stream8 27 | platform: centos 28 | provisioner: 29 | puppet_yum_repo: https://yum.puppetlabs.com/puppetlabs-release-el-8.noarch.rpm 30 | puppet_yum_collections_repo: http://yum.puppetlabs.com/puppet6/puppet6-release-el-8.noarch.rpm 31 | - name: centos-8-puppet7 32 | driver_config: 33 | image: quay.io/centos/centos:stream8 34 | platform: centos 35 | provisioner: 36 | puppet_yum_repo: https://yum.puppetlabs.com/puppetlabs-release-el-8.noarch.rpm 37 | puppet_yum_collections_repo: http://yum.puppetlabs.com/puppet7/puppet7-release-el-8.noarch.rpm 38 | - name: debian-9-puppet6 39 | provisioner: 40 | puppet_apt_repo: https://apt.puppetlabs.com/puppetlabs-release-xenial.deb 41 | puppet_apt_collections_repo: http://apt.puppetlabs.com/puppet6-release-xenial.deb 42 | - name: debian-9-puppet7 43 | provisioner: 44 | puppet_apt_repo: https://apt.puppetlabs.com/puppetlabs-release-xenial.deb 45 | puppet_apt_collections_repo: http://apt.puppetlabs.com/puppet7-release-xenial.deb 46 | - name: debian-10-puppet6 47 | provisioner: 48 | puppet_apt_repo: https://apt.puppetlabs.com/puppetlabs-release-buster.deb 49 | puppet_apt_collections_repo: http://apt.puppetlabs.com/puppet6-release-buster.deb 50 | - name: debian-10-puppet7 51 | provisioner: 52 | puppet_apt_repo: https://apt.puppetlabs.com/puppetlabs-release-buster.deb 53 | puppet_apt_collections_repo: http://apt.puppetlabs.com/puppet7-release-buster.deb 54 | - name: opensuse-15-puppet6 55 | driver_config: 56 | image: opensuse/leap:15 57 | platform: opensuse 58 | provisioner: 59 | custom_pre_install_command: | 60 | sudo zypper addrepo -n puppet6 -f -G http://yum.puppetlabs.com/puppet6/sles/12/x86_64 puppet6 61 | sudo zypper install -y puppet-agent 62 | - name: opensuse-15-puppet7 63 | driver_config: 64 | image: opensuse/leap:15 65 | platform: opensuse 66 | provisioner: 67 | custom_pre_install_command: | 68 | sudo zypper addrepo -n puppet7 -f -G http://yum.puppetlabs.com/puppet7/sles/15/x86_64 puppet7 69 | sudo zypper install -y puppet-agent 70 | - name: oracle-7-puppet6 71 | driver_config: 72 | image: oraclelinux:7 73 | platform: rhel 74 | provisioner: 75 | puppet_yum_repo: https://yum.puppetlabs.com/puppetlabs-release-el-7.noarch.rpm 76 | puppet_yum_collections_repo: http://yum.puppetlabs.com/puppet6/puppet6-release-el-7.noarch.rpm 77 | - name: oracle-7-puppet7 78 | driver_config: 79 | image: oraclelinux:7 80 | platform: rhel 81 | provisioner: 82 | puppet_yum_repo: https://yum.puppetlabs.com/puppetlabs-release-el-7.noarch.rpm 83 | puppet_yum_collections_repo: http://yum.puppetlabs.com/puppet7/puppet7-release-el-7.noarch.rpm 84 | - name: ubuntu-18-04-puppet6 85 | driver_config: 86 | image: ubuntu:18.04 87 | provisioner: 88 | puppet_apt_repo: https://apt.puppetlabs.com/puppetlabs-release-xenial.deb 89 | puppet_apt_collections_repo: http://apt.puppetlabs.com/puppet6-release-bionic.deb 90 | - name: ubuntu-18-04-puppet7 91 | driver_config: 92 | image: ubuntu:18.04 93 | provisioner: 94 | puppet_apt_repo: https://apt.puppetlabs.com/puppetlabs-release-xenial.deb 95 | puppet_apt_collections_repo: http://apt.puppetlabs.com/puppet7-release-bionic.deb 96 | - name: ubuntu-20-04-puppet6 97 | driver_config: 98 | image: ubuntu:20.04 99 | provisioner: 100 | puppet_apt_repo: https://apt.puppetlabs.com/puppetlabs-release-focal.deb 101 | puppet_apt_collections_repo: http://apt.puppetlabs.com/puppet6-release-focal.deb 102 | - name: ubuntu-20-04-puppet7 103 | driver_config: 104 | image: ubuntu:20.04 105 | provisioner: 106 | puppet_apt_repo: https://apt.puppetlabs.com/puppetlabs-release-focal.deb 107 | puppet_apt_collections_repo: http://apt.puppetlabs.com/puppet7-release-focal.deb 108 | 109 | transport: 110 | name: sftp 111 | ssh_key: '~/.ssh/do_ci' 112 | max_wait_until_ready: 30 113 | 114 | verifier: 115 | name: inspec 116 | reporter: 117 | - cli 118 | - junit:.kitchen/logs/%{suite}-%{platform}_inspec.xml 119 | 120 | suites: 121 | - name: digitalocean-linux-baseline 122 | 123 | -------------------------------------------------------------------------------- /kitchen.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | http_proxy: <%= ENV['http_proxy'] %> 4 | https_proxy: <%= ENV['https_proxy'] %> 5 | name: docker 6 | privileged: true 7 | require_chef_omnibus: false 8 | use_sudo: false 9 | 10 | provisioner: 11 | name: puppet_apply 12 | ignore_spec_fixtures: true 13 | manifests_path: test/fixtures/manifests 14 | modules_path: test/fixtures/modules 15 | puppetfile_path: test/fixtures/Puppetfile 16 | require_chef_for_busser: false 17 | 18 | platforms: 19 | - name: centos-7-puppet6 20 | provisioner: 21 | puppet_yum_repo: https://yum.puppetlabs.com/puppetlabs-release-el-7.noarch.rpm 22 | puppet_yum_collections_repo: http://yum.puppetlabs.com/puppet6/puppet6-release-el-7.noarch.rpm 23 | - name: centos-7-puppet7 24 | provisioner: 25 | puppet_yum_repo: https://yum.puppetlabs.com/puppetlabs-release-el-7.noarch.rpm 26 | puppet_yum_collections_repo: http://yum.puppetlabs.com/puppet7/puppet7-release-el-7.noarch.rpm 27 | - name: centos-8-puppet6 28 | driver_config: 29 | image: quay.io/centos/centos:stream8 30 | platform: centos 31 | provisioner: 32 | puppet_yum_repo: https://yum.puppetlabs.com/puppetlabs-release-el-8.noarch.rpm 33 | puppet_yum_collections_repo: http://yum.puppetlabs.com/puppet6/puppet6-release-el-8.noarch.rpm 34 | - name: centos-8-puppet7 35 | driver_config: 36 | image: quay.io/centos/centos:stream8 37 | platform: centos 38 | provisioner: 39 | puppet_yum_repo: https://yum.puppetlabs.com/puppetlabs-release-el-8.noarch.rpm 40 | puppet_yum_collections_repo: http://yum.puppetlabs.com/puppet7/puppet7-release-el-8.noarch.rpm 41 | - name: debian-9-puppet6 42 | provisioner: 43 | puppet_apt_repo: https://apt.puppetlabs.com/puppetlabs-release-xenial.deb 44 | puppet_apt_collections_repo: http://apt.puppetlabs.com/puppet6-release-xenial.deb 45 | - name: debian-9-puppet7 46 | provisioner: 47 | puppet_apt_repo: https://apt.puppetlabs.com/puppetlabs-release-xenial.deb 48 | puppet_apt_collections_repo: http://apt.puppetlabs.com/puppet7-release-xenial.deb 49 | - name: debian-10-puppet6 50 | provisioner: 51 | puppet_apt_repo: https://apt.puppetlabs.com/puppetlabs-release-buster.deb 52 | puppet_apt_collections_repo: http://apt.puppetlabs.com/puppet6-release-buster.deb 53 | - name: debian-10-puppet7 54 | provisioner: 55 | puppet_apt_repo: https://apt.puppetlabs.com/puppetlabs-release-buster.deb 56 | puppet_apt_collections_repo: http://apt.puppetlabs.com/puppet7-release-buster.deb 57 | - name: opensuse-15-puppet6 58 | driver_config: 59 | image: opensuse/leap:15 60 | platform: opensuse 61 | provisioner: 62 | custom_pre_install_command: | 63 | sudo zypper addrepo -n puppet6 -f -G http://yum.puppetlabs.com/puppet6/sles/12/x86_64 puppet6 64 | sudo http_proxy=<%= ENV['http_proxy'] %> https_proxy=<%= ENV['https_proxy'] %> zypper install -y puppet-agent 65 | - name: opensuse-15-puppet7 66 | driver_config: 67 | image: opensuse/leap:15 68 | platform: opensuse 69 | provisioner: 70 | custom_pre_install_command: | 71 | sudo zypper addrepo -n puppet7 -f -G http://yum.puppetlabs.com/puppet7/sles/15/x86_64 puppet7 72 | sudo http_proxy=<%= ENV['http_proxy'] %> https_proxy=<%= ENV['https_proxy'] %> zypper install -y puppet-agent 73 | - name: oracle-7-puppet6 74 | driver_config: 75 | image: oraclelinux:7 76 | platform: rhel 77 | provisioner: 78 | puppet_yum_repo: https://yum.puppetlabs.com/puppetlabs-release-el-7.noarch.rpm 79 | puppet_yum_collections_repo: http://yum.puppetlabs.com/puppet6/puppet6-release-el-7.noarch.rpm 80 | - name: oracle-7-puppet7 81 | driver_config: 82 | image: oraclelinux:7 83 | platform: rhel 84 | provisioner: 85 | puppet_yum_repo: https://yum.puppetlabs.com/puppetlabs-release-el-7.noarch.rpm 86 | puppet_yum_collections_repo: http://yum.puppetlabs.com/puppet7/puppet7-release-el-7.noarch.rpm 87 | - name: ubuntu-18-04-puppet6 88 | driver_config: 89 | image: ubuntu:18.04 90 | provisioner: 91 | puppet_apt_repo: https://apt.puppetlabs.com/puppetlabs-release-xenial.deb 92 | puppet_apt_collections_repo: http://apt.puppetlabs.com/puppet6-release-bionic.deb 93 | - name: ubuntu-18-04-puppet7 94 | driver_config: 95 | image: ubuntu:18.04 96 | provisioner: 97 | puppet_apt_repo: https://apt.puppetlabs.com/puppetlabs-release-xenial.deb 98 | puppet_apt_collections_repo: http://apt.puppetlabs.com/puppet7-release-bionic.deb 99 | - name: ubuntu-20-04-puppet6 100 | driver_config: 101 | image: ubuntu:20.04 102 | provisioner: 103 | puppet_apt_repo: https://apt.puppetlabs.com/puppetlabs-release-focal.deb 104 | puppet_apt_collections_repo: http://apt.puppetlabs.com/puppet6-release-focal.deb 105 | - name: ubuntu-20-04-puppet7 106 | driver_config: 107 | image: ubuntu:20.04 108 | provisioner: 109 | puppet_apt_repo: https://apt.puppetlabs.com/puppetlabs-release-focal.deb 110 | puppet_apt_collections_repo: http://apt.puppetlabs.com/puppet7-release-focal.deb 111 | 112 | transport: 113 | name: docker 114 | 115 | verifier: 116 | name: inspec 117 | reporter: 118 | - cli 119 | - junit:.kitchen/logs/%{suite}-%{platform}_inspec.xml 120 | 121 | suites: 122 | - name: docker-linux-baseline 123 | 124 | -------------------------------------------------------------------------------- /lib/facter/home_users.rb: -------------------------------------------------------------------------------- 1 | # Try to read UID_MIN from /etc/login.defs to calculate SYS_UID_MAX 2 | # if that fails set some predefined values based on os_family fact. 3 | logindefs = '/etc/login.defs' 4 | 5 | if File.exist?(logindefs) 6 | su_maxid = File.readlines(logindefs).each do |line| 7 | break Regexp.last_match[1].to_i - 1 if line =~ %r{^\s*UID_MIN\s+(\d+)(\s*#.*)?$} 8 | end 9 | else 10 | case Facter.value(:osfamily) 11 | when 'Debian', 'OpenBSD', 'FreeBSD' 12 | su_maxid = 999 13 | else 14 | su_maxid = 499 15 | end 16 | end 17 | 18 | # Retrieve all system users and build custom fact with the usernames 19 | # using comma separated values. 20 | Facter.add(:home_users) do 21 | home_users = [] 22 | Etc.passwd do |u| 23 | home_users.push(u.dir) if u.uid > su_maxid && u.uid < 65_000 24 | end 25 | 26 | setcode do 27 | home_users.join(',') 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/facter/manage_access.rb: -------------------------------------------------------------------------------- 1 | # Check if file exists before "managing" them 2 | 3 | checkme = [ 4 | '/etc/anacrontab', 5 | '/etc/crontab', 6 | ] 7 | 8 | Facter.add(:existing) do 9 | setcode do 10 | fex = {} 11 | 12 | checkme.each do |f| 13 | fex[f] = File.exist?(f) 14 | end 15 | 16 | fex 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/facter/retrieve_system_users.rb: -------------------------------------------------------------------------------- 1 | # Try to read UID_MIN from /etc/login.defs to calculate SYS_UID_MAX 2 | # if that fails set some predefined values based on os_family fact. 3 | logindefs = '/etc/login.defs' 4 | 5 | if File.exist?(logindefs) 6 | su_maxid = File.readlines(logindefs).each do |line| 7 | break Regexp.last_match[1].to_i - 1 if line =~ %r{^\s*UID_MIN\s+(\d+)(\s*#.*)?$} 8 | end 9 | else 10 | case Facter.value(:osfamily) 11 | when 'Debian', 'OpenBSD', 'FreeBSD' 12 | su_maxid = 999 13 | else 14 | su_maxid = 499 15 | end 16 | end 17 | 18 | # Retrieve all system users and build custom fact with the usernames 19 | # using comma separated values. 20 | Facter.add(:retrieve_system_users) do 21 | sys_users = [] 22 | Etc.passwd do |u| 23 | sys_users.push(u.name) unless u.uid > su_maxid 24 | end 25 | 26 | setcode do 27 | sys_users.join(',') 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/puppet/functions/combine_sugid_lists.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014, Deutsche Telekom AG 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | Puppet::Functions.create_function(:combine_sugid_lists) do 17 | dispatch :list do 18 | param 'Array', :base 19 | param 'Array', :remove 20 | param 'Array', :add 21 | end 22 | 23 | def list(base, remove, add) 24 | (base - remove + add).uniq 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /manifests/blacklist_files.pp: -------------------------------------------------------------------------------- 1 | # === Copyright 2 | # 3 | # Copyright 2014, Deutsche Telekom AG 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Remove SUID and SGID bits from a given file 8 | 9 | define os_hardening::blacklist_files { 10 | exec { "remove suid/sgid bit from ${name}": 11 | command => "/bin/chmod ug-s ${name}", 12 | # the following checks if we are operating on a file 13 | # and if this file has either SUID or SGID bits set 14 | # it reads: 15 | # (isFile(x) && isSuid(x)) || (isFile(x) && isSgid(x)) 16 | onlyif => "/usr/bin/test -f ${name} -a -u ${name} -o -f ${name} -a -g ${name}", 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /manifests/grub.pp: -------------------------------------------------------------------------------- 1 | # === Copyright 2 | # 3 | # Copyright 2018, Kumina B.V., Tim Stoop 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | 8 | # == Class: os_hardening::grub 9 | # 10 | # Hardens the grub config 11 | # 12 | # @param enable 13 | # 14 | # @param user 15 | # 16 | # @param password_hash 17 | # 18 | # @param boot_without_password 19 | # 20 | class os_hardening::grub ( 21 | Boolean $enable = false, 22 | String $user = 'root', 23 | Optional[String] $password_hash = undef, 24 | Boolean $boot_without_password = true, 25 | ) { 26 | case $facts['os']['name'] { 27 | 'debian', 'ubuntu', 'cumuluslinux': { 28 | $grub_cfg = '/boot/grub/grub.cfg' 29 | $grub_cmd = '/usr/sbin/grub-mkconfig' 30 | } 31 | default: { 32 | $grub_cfg = '/boot/grub2/grub.cfg' 33 | $grub_cmd = '/usr/sbin/grub2-mkconfig' 34 | } 35 | } 36 | 37 | if $enable { 38 | file { '/etc/grub.d/01_hardening': 39 | content => template('os_hardening/grub_hardening.erb'), 40 | notify => Exec['Grub configuration recreate for os_hardening::grub'], 41 | mode => '0755', 42 | } 43 | 44 | file { $grub_cfg: 45 | owner => 'root', 46 | group => 'root', 47 | mode => '0600', 48 | } 49 | 50 | if $boot_without_password { 51 | # This sets up Grub on Debian Stretch so you can still boot the system without a password 52 | exec { 'Keep system bootable without credentials': 53 | command => "/bin/sed -i -e 's/^CLASS=\"\\(.*\\)\"/CLASS=\"\\1 --unrestricted\"/' /etc/grub.d/10_linux;", 54 | unless => '/bin/grep -e "^CLASS=" /etc/grub.d/10_linux | /bin/grep -q -- "--unrestricted"', 55 | notify => Exec['Grub configuration recreate for os_hardening::grub'], 56 | } 57 | } else { 58 | exec { 'Remove addition for keeping system bootable without credentials': 59 | command => "/bin/sed -i -e 's/^CLASS=\"\\(.*\\) --unrestricted\\(.*\\)\"/CLASS=\"\\1\\2\"/' /etc/grub.d/10_linux;", 60 | onlyif => '/bin/grep -e "^CLASS=" /etc/grub.d/10_linux | /bin/grep -q -- "--unrestricted"', 61 | notify => Exec['Grub configuration recreate for os_hardening::grub'], 62 | } 63 | } 64 | } else { 65 | file { '/etc/grub.d/01_hardening': 66 | ensure => absent, 67 | notify => Exec['Grub configuration recreate for os_hardening::grub'], 68 | } 69 | } 70 | 71 | exec { 'Grub configuration recreate for os_hardening::grub': 72 | command => "${grub_cmd} -o ${grub_cfg}", 73 | refreshonly => true, 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /manifests/init.pp: -------------------------------------------------------------------------------- 1 | # === Copyright 2 | # 3 | # Copyright 2014, Deutsche Telekom AG 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | 8 | # == Class: os_hardening 9 | # 10 | # Pulls in all manifests for os_hardening. 11 | # 12 | # @param system_environment 13 | # 14 | # @param pe_environment 15 | # 16 | # @param extra_user_paths 17 | # 18 | # @param umask 19 | # 20 | # @param maildir 21 | # 22 | # @param usergroups 23 | # 24 | # @param sys_uid_min 25 | # 26 | # @param sys_gid_min 27 | # 28 | # @param password_max_age 29 | # 30 | # @param password_min_age 31 | # 32 | # @param password_warn_age 33 | # 34 | # @param login_retries 35 | # 36 | # @param login_timeout 37 | # 38 | # @param chfn_restrict 39 | # 40 | # @param allow_login_without_home 41 | # 42 | # @param allow_change_user 43 | # 44 | # @param manage_home_permissions 45 | # 46 | # @param manage_log_permissions 47 | # 48 | # @param manage_cron_permissions 49 | # 50 | # @param manage_system_users 51 | # 52 | # @param ignore_users 53 | # 54 | # @param ignore_home_users 55 | # 56 | # @param ignore_restrict_log_dir 57 | # 58 | # @param ignore_files_in_folder_to_restrict 59 | # 60 | # @param folders_to_restrict 61 | # 62 | # @param ignore_max_files_warnings 63 | # 64 | # @param restrict_log_dir 65 | # 66 | # @param recurselimit 67 | # 68 | # @param passwdqc_enabled 69 | # 70 | # @param auth_retries 71 | # 72 | # @param auth_lockout_time 73 | # 74 | # @param passwdqc_options 75 | # 76 | # @param manage_pam_unix 77 | # 78 | # @param enable_pw_history 79 | # 80 | # @param pw_remember_last 81 | # 82 | # @param only_root_may_su 83 | # 84 | # @param root_ttys 85 | # 86 | # @param whitelist 87 | # 88 | # @param blacklist 89 | # 90 | # @param remove_from_unknown 91 | # 92 | # @param dry_run_on_unknown 93 | # 94 | # @param enable_module_loading 95 | # 96 | # @param load_modules 97 | # 98 | # @param disable_filesystems 99 | # 100 | # @param cpu_vendor 101 | # 102 | # @param icmp_ratelimit 103 | # 104 | # @param desktop_enabled 105 | # 106 | # @param enable_ipv4_forwarding 107 | # 108 | # @param manage_ipv6 109 | # 110 | # @param enable_ipv6 111 | # 112 | # @param enable_ipv6_forwarding 113 | # 114 | # @param arp_restricted 115 | # 116 | # @param arp_ignore_samenet 117 | # 118 | # @param enable_sysrq 119 | # 120 | # @param enable_core_dump 121 | # 122 | # @param enable_stack_protection 123 | # 124 | # @param enable_rpfilter 125 | # 126 | # @param rpfilter_loose 127 | # 128 | # @param enable_log_martians 129 | # 130 | # @param unwanted_packages 131 | # 132 | # @param wanted_packages 133 | # 134 | # @param disabled_services 135 | # 136 | # @param enable_grub_hardening 137 | # 138 | # @param grub_user 139 | # 140 | # @param grub_password_hash 141 | # 142 | # @param boot_without_password 143 | # 144 | # @param enable_sysctl_config 145 | # 146 | # @param system_umask 147 | # 148 | # @param shadow_group 149 | # 150 | # @param shadow_mode 151 | # 152 | class os_hardening ( 153 | String $system_environment = 'default', 154 | Boolean $pe_environment = false, 155 | Array $extra_user_paths = [], 156 | Optional[String] $umask = undef, 157 | Optional[String] $maildir = undef, 158 | Boolean $usergroups = true, 159 | Optional[Integer] $sys_uid_min = undef, 160 | Optional[Integer] $sys_gid_min = undef, 161 | Integer $password_max_age = 60, 162 | Integer $password_min_age = 7, 163 | Integer $password_warn_age = 7, 164 | Integer $login_retries = 5, 165 | Integer $login_timeout = 60, 166 | Optional[String] $chfn_restrict = undef, 167 | Boolean $allow_login_without_home = false, 168 | Boolean $allow_change_user = false, 169 | Boolean $manage_home_permissions = false, 170 | Boolean $manage_log_permissions = false, 171 | Boolean $manage_cron_permissions = false, 172 | Boolean $manage_system_users = true, 173 | Array $ignore_users = [], 174 | Array $ignore_home_users = [], 175 | Array $ignore_restrict_log_dir = [], 176 | Array $ignore_files_in_folder_to_restrict = [], 177 | Array $folders_to_restrict = ['/usr/local/games','/usr/local/sbin','/usr/local/bin','/usr/bin','/usr/sbin','/sbin','/bin'], 178 | Boolean $ignore_max_files_warnings = false, 179 | Array $restrict_log_dir = ['/var/log/'], 180 | Integer $recurselimit = 5, 181 | Boolean $passwdqc_enabled = true, 182 | Integer $auth_retries = 5, 183 | Integer $auth_lockout_time = 600, 184 | String $passwdqc_options = 'min=disabled,disabled,16,12,8', 185 | Boolean $manage_pam_unix = false, 186 | Boolean $enable_pw_history = true, 187 | Integer $pw_remember_last = 5, 188 | Boolean $only_root_may_su = false, 189 | Array $root_ttys = ['console','tty1','tty2','tty3','tty4','tty5','tty6'], 190 | Array $whitelist = [], 191 | Array $blacklist = [], 192 | Boolean $remove_from_unknown = false, 193 | Boolean $dry_run_on_unknown = false, 194 | Boolean $enable_module_loading = true, 195 | Array $load_modules = [], 196 | Array $disable_filesystems = ['cramfs','freevxfs','jffs2','hfs','hfsplus','squashfs','udf'], 197 | String $cpu_vendor = 'intel', 198 | String $icmp_ratelimit = '100', 199 | Boolean $desktop_enabled = false, 200 | Boolean $enable_ipv4_forwarding = false, 201 | Boolean $manage_ipv6 = true, 202 | Boolean $enable_ipv6 = false, 203 | Boolean $enable_ipv6_forwarding = false, 204 | Boolean $arp_restricted = true, 205 | Boolean $arp_ignore_samenet = false, 206 | Boolean $enable_sysrq = false, 207 | Boolean $enable_core_dump = false, 208 | Boolean $enable_stack_protection = true, 209 | Boolean $enable_rpfilter = true, 210 | Boolean $rpfilter_loose = false, 211 | Boolean $enable_log_martians = true, 212 | Array $unwanted_packages = [], 213 | Array $wanted_packages = [], 214 | Array $disabled_services = [], 215 | Boolean $enable_grub_hardening = false, 216 | String $grub_user = 'root', 217 | Optional[String] $grub_password_hash = undef, 218 | Boolean $boot_without_password = true, 219 | Boolean $enable_sysctl_config = true, 220 | Optional[String] $system_umask = undef, 221 | Optional[String] $shadow_group = undef, 222 | Optional[String] $shadow_mode = undef, 223 | ) { 224 | # Prepare 225 | # ------- 226 | 227 | # system environment configuration 228 | # there may be differences when using kvm/lxc vs metal 229 | 230 | # sysctl configuration doesn't work in docker: 231 | $configure_sysctl = ( 232 | $system_environment != 'lxc' and 233 | $system_environment != 'docker' and 234 | $enable_sysctl_config 235 | ) 236 | 237 | # Defaults for specific platforms 238 | case $facts['os']['family'] { 239 | 'Debian','Suse': { 240 | $def_umask = '027' 241 | $def_sys_uid_min = 100 242 | $def_sys_gid_min = 100 243 | $def_shadowgroup = 'shadow' 244 | $def_shadowmode = '0640' 245 | } 246 | 'RedHat': { 247 | $def_umask = '077' 248 | $def_sys_uid_min = 201 249 | $def_sys_gid_min = 201 250 | $def_shadowgroup = 'root' 251 | $def_shadowmode = '0000' 252 | } 253 | default: { 254 | $def_umask = '027' 255 | $def_sys_uid_min = 100 256 | $def_sys_gid_min = 100 257 | $def_shadowgroup = 'root' 258 | $def_shadowmode = '0600' 259 | } 260 | } 261 | 262 | # Merge defaults 263 | $merged_umask = pick($umask, $def_umask) 264 | $merged_sys_uid_min = pick($sys_uid_min, $def_sys_uid_min) 265 | $merged_sys_gid_min = pick($sys_gid_min, $def_sys_gid_min) 266 | $merged_shadowgroup = pick($shadow_group, $def_shadowgroup) 267 | $merged_shadowmode = pick($shadow_mode, $def_shadowmode) 268 | 269 | # Fix for Puppet Enterprise 270 | if $pe_environment { 271 | # Don't redefine directory 272 | $folders_to_restrict_int = delete($folders_to_restrict, '/usr/local/bin') 273 | } else { 274 | $folders_to_restrict_int = $folders_to_restrict 275 | } 276 | 277 | # Install 278 | # ------- 279 | class { 'os_hardening::limits': 280 | enable_core_dump => $enable_core_dump, 281 | } 282 | class { 'os_hardening::login_defs': 283 | extra_user_paths => $extra_user_paths, 284 | umask => $merged_umask, 285 | maildir => $maildir, 286 | usergroups => $usergroups, 287 | sys_uid_min => $merged_sys_uid_min, 288 | sys_gid_min => $merged_sys_gid_min, 289 | password_max_age => $password_max_age, 290 | password_min_age => $password_min_age, 291 | password_warn_age => $password_warn_age, 292 | login_retries => $login_retries, 293 | login_timeout => $login_timeout, 294 | chfn_restrict => $chfn_restrict, 295 | allow_login_without_home => $allow_login_without_home, 296 | } 297 | class { 'os_hardening::minimize_access': 298 | allow_change_user => $allow_change_user, 299 | manage_home_permissions => $manage_home_permissions, 300 | manage_log_permissions => $manage_log_permissions, 301 | manage_cron_permissions => $manage_cron_permissions, 302 | manage_system_users => $manage_system_users, 303 | ignore_users => $ignore_users, 304 | ignore_home_users => $ignore_home_users, 305 | ignore_restrict_log_dir => $ignore_restrict_log_dir, 306 | ignore_files_in_folder_to_restrict => $ignore_files_in_folder_to_restrict, 307 | folders_to_restrict => $folders_to_restrict_int, 308 | ignore_max_files_warnings => $ignore_max_files_warnings, 309 | restrict_log_dir => $restrict_log_dir, 310 | shadowgroup => $merged_shadowgroup, 311 | shadowmode => $merged_shadowmode, 312 | recurselimit => $recurselimit, 313 | } 314 | class { 'os_hardening::modules': 315 | disable_filesystems => $disable_filesystems, 316 | } 317 | class { 'os_hardening::pam': 318 | passwdqc_enabled => $passwdqc_enabled, 319 | auth_retries => $auth_retries, 320 | auth_lockout_time => $auth_lockout_time, 321 | passwdqc_options => $passwdqc_options, 322 | manage_pam_unix => $manage_pam_unix, 323 | enable_pw_history => $enable_pw_history, 324 | pw_remember_last => $pw_remember_last, 325 | only_root_may_su => $only_root_may_su, 326 | } 327 | class { 'os_hardening::profile': 328 | enable_core_dump => $enable_core_dump, 329 | } 330 | class { 'os_hardening::securetty': 331 | root_ttys => $root_ttys, 332 | } 333 | class { 'os_hardening::suid_sgid': 334 | whitelist => $whitelist, 335 | blacklist => $blacklist, 336 | remove_from_unknown => $remove_from_unknown, 337 | dry_run_on_unknown => $dry_run_on_unknown, 338 | } 339 | 340 | if $configure_sysctl { 341 | class { 'os_hardening::sysctl': 342 | enable_module_loading => $enable_module_loading, 343 | load_modules => $load_modules, 344 | cpu_vendor => $cpu_vendor, 345 | icmp_ratelimit => $icmp_ratelimit, 346 | desktop_enabled => $desktop_enabled, 347 | enable_ipv4_forwarding => $enable_ipv4_forwarding, 348 | manage_ipv6 => $manage_ipv6, 349 | enable_ipv6 => $enable_ipv6, 350 | enable_ipv6_forwarding => $enable_ipv6_forwarding, 351 | arp_restricted => $arp_restricted, 352 | arp_ignore_samenet => $arp_ignore_samenet, 353 | enable_sysrq => $enable_sysrq, 354 | enable_core_dump => $enable_core_dump, 355 | enable_stack_protection => $enable_stack_protection, 356 | enable_rpfilter => $enable_rpfilter, 357 | rpfilter_loose => $rpfilter_loose, 358 | enable_log_martians => $enable_log_martians, 359 | } 360 | } 361 | 362 | class { 'os_hardening::services': 363 | unwanted_packages => $unwanted_packages, 364 | wanted_packages => $wanted_packages, 365 | disabled_services => $disabled_services, 366 | } 367 | 368 | class { 'os_hardening::grub': 369 | enable => $enable_grub_hardening, 370 | user => $grub_user, 371 | password_hash => $grub_password_hash, 372 | boot_without_password => $boot_without_password, 373 | } 374 | 375 | class { 'os_hardening::umask': 376 | system_umask => $system_umask, 377 | } 378 | } 379 | -------------------------------------------------------------------------------- /manifests/limits.pp: -------------------------------------------------------------------------------- 1 | # === Copyright 2 | # 3 | # Copyright 2014, Deutsche Telekom AG 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | 8 | # == Class: os_hardening::limits 9 | # 10 | # Configures the limits.conf. Sets: 11 | # 12 | # * disable core dumps 13 | # 14 | # @param enable_core_dump 15 | # 16 | class os_hardening::limits ( 17 | Boolean $enable_core_dump = false, 18 | ) { 19 | if $enable_core_dump == false { 20 | file { '/etc/security/limits.d/10.hardcore.conf': 21 | ensure => file, 22 | source => 'puppet:///modules/os_hardening/limits.conf', 23 | owner => 'root', 24 | group => 'root', 25 | mode => '0400', 26 | } 27 | } else { 28 | file { '/etc/security/limits.d/10.hardcore.conf': 29 | ensure => absent, 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /manifests/login_defs.pp: -------------------------------------------------------------------------------- 1 | # === Copyright 2 | # 3 | # Copyright 2014, Deutsche Telekom AG 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | 8 | # == Class: os_hardening::pam 9 | # 10 | # Configures PAM 11 | # 12 | # @param extra_user_paths 13 | # 14 | # @param umask 15 | # 16 | # @param maildir 17 | # 18 | # @param usergroups 19 | # 20 | # @param sys_uid_min 21 | # 22 | # @param sys_gid_min 23 | # 24 | # @param password_max_age 25 | # 26 | # @param password_min_age 27 | # 28 | # @param password_warn_age 29 | # 30 | # @param login_retries 31 | # 32 | # @param login_timeout 33 | # 34 | # @param chfn_restrict 35 | # 36 | # @param allow_login_without_home 37 | # 38 | class os_hardening::login_defs ( 39 | Array $extra_user_paths = [], 40 | String $umask = '027', 41 | String $maildir = '/var/mail', 42 | Boolean $usergroups = true, 43 | Integer $sys_uid_min = 100, 44 | Integer $sys_gid_min = 100, 45 | Integer $password_max_age = 60, 46 | Integer $password_min_age = 7, 47 | Integer $password_warn_age = 7, 48 | Integer $login_retries = 5, 49 | Integer $login_timeout = 60, 50 | Optional[String] $chfn_restrict = undef, 51 | Boolean $allow_login_without_home = false, 52 | ) { 53 | # prepare all variables 54 | $additional_user_paths = join($extra_user_paths, ':') 55 | 56 | # convert bool to yes/no 57 | $usergroups_yn = bool2str($usergroups, 'yes', 'no') 58 | 59 | # set the file 60 | file { '/etc/login.defs': 61 | ensure => file, 62 | content => template('os_hardening/login.defs.erb'), 63 | owner => 'root', 64 | group => 'root', 65 | mode => '0444', 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /manifests/minimize_access.pp: -------------------------------------------------------------------------------- 1 | # === Copyright 2 | # 3 | # Copyright 2014, Deutsche Telekom AG 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | 8 | # == Class: os_hardening::minimize_access 9 | # 10 | # Configures profile.conf. 11 | # 12 | # @param allow_change_user 13 | # 14 | # @param ignore_max_files_warnings 15 | # 16 | # @param manage_home_permissions 17 | # 18 | # @param manage_log_permissions 19 | # 20 | # @param manage_cron_permissions 21 | # 22 | # @param manage_system_users 23 | # 24 | # @param always_ignore_users 25 | # 26 | # @param ignore_users 27 | # 28 | # @param ignore_home_users 29 | # 30 | # @param ignore_restrict_log_dir 31 | # 32 | # @param ignore_files_in_folder_to_restrict 33 | # 34 | # @param folders_to_restrict 35 | # 36 | # @param restrict_log_dir 37 | # 38 | # @param shadowgroup 39 | # 40 | # @param shadowmode 41 | # 42 | # @param recurselimit 43 | # 44 | class os_hardening::minimize_access ( 45 | Boolean $allow_change_user = false, 46 | Boolean $ignore_max_files_warnings = false, 47 | Boolean $manage_home_permissions = false, 48 | Boolean $manage_log_permissions = false, 49 | Boolean $manage_cron_permissions = false, 50 | Boolean $manage_system_users = true, 51 | Array $always_ignore_users = ['root','sync','shutdown','halt'], 52 | Array $ignore_users = [], 53 | Array $ignore_home_users = [], 54 | Array $ignore_restrict_log_dir = [], 55 | Array $ignore_files_in_folder_to_restrict = [], 56 | Array $folders_to_restrict = ['/usr/local/games','/usr/local/sbin','/usr/local/bin','/usr/bin','/usr/sbin','/sbin','/bin'], 57 | Array $restrict_log_dir = ['/var/log/'], 58 | String $shadowgroup = 'root', 59 | String $shadowmode = '0600', 60 | Integer $recurselimit = 5, 61 | ) { 62 | case $facts['os']['name'] { 63 | 'redhat', 'fedora': { 64 | $nologin_path = '/sbin/nologin' 65 | $shadow_path = ['/etc/shadow', '/etc/gshadow'] 66 | } 67 | 'debian', 'ubuntu', 'cumuluslinux': { 68 | $nologin_path = '/usr/sbin/nologin' 69 | $shadow_path = ['/etc/shadow', '/etc/gshadow'] 70 | } 71 | default: { 72 | $nologin_path = '/sbin/nologin' 73 | $shadow_path = '/etc/shadow' 74 | } 75 | } 76 | 77 | # Whether $folders_to_restrict should issue warnings if the puppet max_files 78 | # file resource exceeds the default soft limit of 1000 on recursive file 79 | # resources, /bin and /usr/bin can exceed this default limit 80 | if $ignore_max_files_warnings { 81 | $use_max_files = -1 82 | } else { 83 | $use_max_files = 0 84 | } 85 | case $facts['aio_agent_version'] { 86 | /^6/: { 87 | if versioncmp($facts['aio_agent_version'], '6.23.0') >= 0 { 88 | $apply_max_files = true 89 | } else { 90 | $apply_max_files = false 91 | } 92 | } 93 | /^7/: { 94 | if versioncmp($facts['aio_agent_version'], '7.7.0') >= 0 { 95 | $apply_max_files = true 96 | } else { 97 | $apply_max_files = false 98 | } 99 | } 100 | default: { 101 | $apply_max_files = true 102 | } 103 | } 104 | 105 | # remove write permissions from path folders ($PATH) for all regular users 106 | # this prevents changing any system-wide command from normal users 107 | if $apply_max_files { 108 | ensure_resources ('file', 109 | { $folders_to_restrict => { 110 | ensure => directory, 111 | ignore => $ignore_files_in_folder_to_restrict, 112 | links => follow, 113 | mode => 'go-w', 114 | recurse => true, 115 | recurselimit => $recurselimit, 116 | selinux_ignore_defaults => true, 117 | max_files => $use_max_files, 118 | } 119 | }) 120 | } else { 121 | # Original pre the introduction of max_files in puppet-agent 6.23.0/7.70 122 | ensure_resources ('file', 123 | { $folders_to_restrict => { 124 | ensure => directory, 125 | ignore => $ignore_files_in_folder_to_restrict, 126 | links => follow, 127 | mode => 'go-w', 128 | recurse => true, 129 | recurselimit => $recurselimit, 130 | selinux_ignore_defaults => true, 131 | } 132 | }) 133 | } 134 | # Added users with homes 135 | $homes_users = split($facts['home_users'], ',') 136 | 137 | # added ignore these homes 138 | $target_home_users = difference($homes_users, $ignore_home_users) 139 | 140 | # added homes to restrict 141 | if $manage_home_permissions == true { 142 | ensure_resources ('file', 143 | { $target_home_users => { 144 | ensure => directory, 145 | links => follow, 146 | mode => 'g-w,o-rwx', 147 | recurse => true, 148 | recurselimit => $recurselimit, 149 | } 150 | }) 151 | } 152 | 153 | # ensure log folders have right permissions 154 | if $manage_log_permissions == true { 155 | ensure_resources ('file', 156 | { $restrict_log_dir => { 157 | ensure => directory, 158 | ignore => $ignore_restrict_log_dir, 159 | links => follow, 160 | mode => 'g-wx,o-rwx', 161 | recurse => true, 162 | recurselimit => $recurselimit, 163 | } 164 | }) 165 | } 166 | 167 | # ensure crontab have right permissions 168 | if $manage_cron_permissions == true { 169 | $cronfiles = ['/etc/anacrontab', '/etc/crontab'] 170 | $cronfiles.each |String $cronfile| { 171 | if ($facts['existing'][$cronfile]) { 172 | file { $cronfile: 173 | ensure => file, 174 | mode => 'og-rwx', 175 | owner => 'root', 176 | group => 'root', 177 | } 178 | } 179 | } 180 | 181 | # ensure cron hourly have right permissions 182 | ensure_resources ('file', 183 | { '/etc/cron.hourly' => { 184 | ensure => directory, 185 | mode => 'og-rwx', 186 | owner => 'root', 187 | group => 'root', 188 | links => follow, 189 | recurse => true, 190 | recurselimit => $recurselimit, 191 | } 192 | }) 193 | 194 | # ensure cron daily have right permissions 195 | ensure_resources ('file', 196 | { '/etc/cron.daily' => { 197 | ensure => directory, 198 | mode => 'og-rwx', 199 | owner => 'root', 200 | group => 'root', 201 | links => follow, 202 | recurse => true, 203 | recurselimit => $recurselimit, 204 | } 205 | }) 206 | 207 | # ensure cron weekly have right permissions 208 | ensure_resources ('file', 209 | { '/etc/cron.weekly' => { 210 | ensure => directory, 211 | mode => 'og-rwx', 212 | owner => 'root', 213 | group => 'root', 214 | links => follow, 215 | recurse => true, 216 | recurselimit => $recurselimit, 217 | } 218 | }) 219 | 220 | # ensure cron monthly have right permissions 221 | ensure_resources ('file', 222 | { '/etc/cron.monthly' => { 223 | ensure => directory, 224 | mode => 'og-rwx', 225 | owner => 'root', 226 | group => 'root', 227 | links => follow, 228 | recurse => true, 229 | recurselimit => $recurselimit, 230 | } 231 | }) 232 | 233 | # ensure cron.d have right permissions 234 | ensure_resources ('file', 235 | { '/etc/cron.d' => { 236 | ensure => directory, 237 | mode => 'og-rwx', 238 | owner => 'root', 239 | group => 'root', 240 | links => follow, 241 | recurse => true, 242 | recurselimit => $recurselimit, 243 | } 244 | }) 245 | 246 | # ensure cron.deny and at.deny is absent 247 | file { '/etc/cron.deny': 248 | ensure => absent, 249 | } 250 | 251 | file { '/etc/at.deny': 252 | ensure => absent, 253 | } 254 | 255 | # ensure cron.allow is there 256 | file { '/etc/cron.allow': 257 | ensure => file, 258 | owner => 'root', 259 | group => 'root', 260 | mode => 'og-rwx', 261 | } 262 | 263 | # ensure at.allow is there 264 | file { '/etc/at.allow': 265 | ensure => file, 266 | owner => 'root', 267 | group => 'root', 268 | mode => 'og-rwx', 269 | } 270 | } 271 | 272 | # shadow must only be accessible to user root 273 | file { $shadow_path: 274 | ensure => file, 275 | owner => 'root', 276 | group => $shadowgroup, 277 | mode => $shadowmode, 278 | } 279 | 280 | # su must only be accessible to user and group root 281 | if $allow_change_user == false { 282 | file { '/bin/su': 283 | ensure => file, 284 | links => follow, 285 | owner => 'root', 286 | group => 'root', 287 | mode => '0750', 288 | } 289 | } else { 290 | file { '/bin/su': 291 | ensure => file, 292 | links => follow, 293 | owner => 'root', 294 | group => 'root', 295 | mode => '4755', 296 | } 297 | } 298 | 299 | if $manage_system_users == true { 300 | # retrieve system users through custom fact 301 | $system_users = split($facts['retrieve_system_users'], ',') 302 | 303 | # build array of usernames we need to verify/change 304 | $ignore_users_arr = union($always_ignore_users, $ignore_users) 305 | 306 | # build a target array with usernames to verify/change 307 | $target_system_users = difference($system_users, $ignore_users_arr) 308 | 309 | # ensure accounts are locked (no password) and use nologin shell 310 | user { $target_system_users: 311 | ensure => present, 312 | shell => $nologin_path, 313 | password => '*', 314 | } 315 | } 316 | } 317 | -------------------------------------------------------------------------------- /manifests/modules.pp: -------------------------------------------------------------------------------- 1 | # === Copyright 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # http://www.apache.org/licenses/LICENSE-2.0 5 | # 6 | 7 | # == Class: os_hardening::modules 8 | # 9 | # Manage Kernel Modules 10 | # 11 | # @param disable_filesystems 12 | # 13 | class os_hardening::modules ( 14 | Array $disable_filesystems = ['cramfs','freevxfs','jffs2','hfs','hfsplus','squashfs','udf'], 15 | ) { 16 | # Disable unused filesystems (os-10) 17 | file { '/etc/modprobe.d/dev-sec.conf': 18 | ensure => file, 19 | owner => 'root', 20 | group => 'root', 21 | mode => '0440', 22 | content => template('os_hardening/disable_fs.erb'), 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /manifests/pam.pp: -------------------------------------------------------------------------------- 1 | # === Copyright 2 | # 3 | # Copyright 2014, Deutsche Telekom AG 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | 8 | # == Class: os_hardening::pam 9 | # 10 | # Configures PAM 11 | # 12 | # @param passwdqc_enabled 13 | # 14 | # @param auth_retries 15 | # 16 | # @param auth_lockout_time 17 | # 18 | # @param passwdqc_options 19 | # 20 | # @param manage_pam_unix 21 | # 22 | # @param enable_pw_history 23 | # 24 | # @param pw_remember_last 25 | # 26 | # @param only_root_may_su 27 | # 28 | class os_hardening::pam ( 29 | Boolean $passwdqc_enabled = true, 30 | Integer $auth_retries = 5, 31 | Integer $auth_lockout_time = 600, 32 | String $passwdqc_options = 'min=disabled,disabled,16,12,8', 33 | Boolean $manage_pam_unix = false, 34 | Boolean $enable_pw_history = false, 35 | Integer $pw_remember_last = 5, 36 | Boolean $only_root_may_su = false, 37 | ) { 38 | # prepare package names 39 | case $facts['os']['name'] { 40 | 'redhat', 'fedora': { 41 | $pam_ccreds = 'pam_ccreds' 42 | $pam_passwdqc = 'pam_passwdqc' 43 | $pam_cracklib = 'pam_cracklib' 44 | } 45 | 'debian', 'ubuntu', 'cumuluslinux': { 46 | $pam_ccreds = 'libpam-ccreds' 47 | $pam_passwdqc = 'libpam-passwdqc' 48 | $pam_cracklib = 'libpam-cracklib' 49 | } 50 | default: { 51 | $pam_ccreds = 'pam_ccreds' 52 | $pam_passwdqc = 'pam_passwdqc' 53 | $pam_cracklib = 'pam_cracklib' 54 | } 55 | } 56 | 57 | # remove ccreds if not necessary 58 | package { 'pam-ccreds': 59 | ensure => absent, 60 | name => $pam_ccreds, 61 | } 62 | 63 | case $facts['os']['name'] { 64 | 'debian', 'ubuntu', 'cumuluslinux': { 65 | # configure paths 66 | $passwdqc_path = '/usr/share/pam-configs/passwdqc' 67 | $tally2_path = '/usr/share/pam-configs/tally2' 68 | $unix_path = '/usr/share/pam-configs/unix' 69 | $su_path = '/etc/pam.d/su' 70 | 71 | # if passwdqc is enabled 72 | if $passwdqc_enabled == true { 73 | # remove pam_cracklib, because it does not play nice with passwdqc 74 | package { 'pam-cracklib': 75 | ensure => absent, 76 | name => $pam_cracklib, 77 | } 78 | 79 | # get the package for strong password checking 80 | package { 'pam-passwdqc': 81 | ensure => present, 82 | name => $pam_passwdqc, 83 | } 84 | 85 | # configure passwdqc via central module: 86 | file { $passwdqc_path: 87 | ensure => file, 88 | content => template('os_hardening/pam_passwdqc.erb'), 89 | owner => 'root', 90 | group => 'root', 91 | mode => '0640', 92 | require => Package['pam-passwdqc'], 93 | notify => Exec['update-pam'], 94 | } 95 | } else { 96 | # deactivate passwdqc 97 | 98 | # delete passwdqc file on ubuntu and debian 99 | file { $passwdqc_path: 100 | ensure => absent, 101 | notify => Exec['update-pam'], 102 | } 103 | 104 | # make sure the package is not on the system, 105 | # if this feature is not wanted 106 | package { 'pam-passwdqc': 107 | ensure => absent, 108 | name => $pam_passwdqc, 109 | } 110 | } 111 | 112 | #configure tally2 113 | if $auth_retries > 0 { 114 | # tally2 is needed for pam 115 | package { 'libpam-modules': 116 | ensure => present, 117 | } 118 | 119 | file { $tally2_path: 120 | ensure => file, 121 | content => template('os_hardening/pam_tally2.erb'), 122 | owner => 'root', 123 | group => 'root', 124 | mode => '0640', 125 | notify => Exec['update-pam'], 126 | } 127 | } else { 128 | file { $tally2_path: 129 | ensure => absent, 130 | notify => Exec['update-pam'], 131 | } 132 | } 133 | 134 | #configure pam_unix with password history 135 | if $manage_pam_unix { 136 | if $enable_pw_history { 137 | $pw_history_options = "remember=${pw_remember_last}" 138 | } else { 139 | $pw_history_options = '' 140 | } 141 | file { $unix_path: 142 | ensure => file, 143 | content => template('os_hardening/pam_unix.erb'), 144 | owner => 'root', 145 | group => 'root', 146 | mode => '0640', 147 | notify => Exec['update-pam'], 148 | } 149 | } 150 | 151 | #only allow root and members of the group wheel to su 152 | file { $su_path: 153 | ensure => file, 154 | content => template('os_hardening/pam_su_debian_ubuntu.erb'), 155 | owner => 'root', 156 | group => 'root', 157 | mode => '0640', 158 | } 159 | 160 | exec { 'update-pam': 161 | command => '/usr/sbin/pam-auth-update --package', 162 | refreshonly => true, 163 | } 164 | } 165 | 166 | # others ... 167 | default: { 168 | # TODO: not supported warning 169 | } 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /manifests/profile.pp: -------------------------------------------------------------------------------- 1 | # === Copyright 2 | # 3 | # Copyright 2014, Deutsche Telekom AG 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | 8 | # == Class: os_hardening::profile 9 | # 10 | # Configures profile.conf. 11 | # 12 | # @param enable_core_dump 13 | # 14 | class os_hardening::profile ( 15 | Boolean $enable_core_dump = false, 16 | ) { 17 | if $enable_core_dump == false { 18 | file { '/etc/profile.d/pinerolo_profile.sh': 19 | ensure => file, 20 | source => 'puppet:///modules/os_hardening/profile.conf', 21 | owner => 'root', 22 | group => 'root', 23 | mode => '0400', 24 | } 25 | } else { 26 | file { '/etc/profile.d/pinerolo_profile.sh': 27 | ensure => absent, 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /manifests/securetty.pp: -------------------------------------------------------------------------------- 1 | # === Copyright 2 | # 3 | # Copyright 2014, Deutsche Telekom AG 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | 8 | # == Class: os_hardening::securetty 9 | # 10 | # Configures securetty. 11 | # 12 | # @param root_ttys 13 | # 14 | class os_hardening::securetty ( 15 | Array $root_ttys = ['console','tty1','tty2','tty3','tty4','tty5','tty6'], 16 | ) { 17 | $ttys = join($root_ttys, "\n") 18 | file { '/etc/securetty': 19 | ensure => file, 20 | content => template('os_hardening/securetty.erb'), 21 | owner => 'root', 22 | group => 'root', 23 | mode => '0400', 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /manifests/services.pp: -------------------------------------------------------------------------------- 1 | # === Copyright 2 | # 3 | # Copyright 2018, Kumina B.V., Tim Stoop 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | 8 | # == Class: os_hardening::services 9 | # 10 | # Configures specific services that do not require a full class of their own 11 | # 12 | # @param unwanted_packages 13 | # 14 | # @param wanted_packages 15 | # 16 | # @param disabled_services 17 | # 18 | class os_hardening::services ( 19 | Array $unwanted_packages = [], 20 | Array $wanted_packages = [], 21 | Array $disabled_services = [], 22 | ) { 23 | # Remove packages that should not be installed 24 | $unwanted_packages.each |String $package| { 25 | package { $package: 26 | ensure => purged, 27 | } 28 | } 29 | 30 | # Add packages that should be installed 31 | $wanted_packages.each |String $package| { 32 | package { $package: 33 | ensure => installed, 34 | } 35 | } 36 | 37 | # Disable services that are not wanted 38 | $disabled_services.each |String $service| { 39 | service { $service: 40 | ensure => stopped, 41 | enable => false, 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /manifests/suid_sgid.pp: -------------------------------------------------------------------------------- 1 | # === Copyright 2 | # 3 | # Copyright 2014, Deutsche Telekom AG 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | 8 | # == Class: os_hardening::suid_sgid 9 | # 10 | # Minimize SUID and SGID bits. 11 | # 12 | # @param whitelist 13 | # 14 | # @param blacklist 15 | # 16 | # @param remove_from_unknown 17 | # 18 | # @param dry_run_on_unknown 19 | # 20 | class os_hardening::suid_sgid ( 21 | Array $whitelist = [], 22 | Array $blacklist = [], 23 | Boolean $remove_from_unknown = false, 24 | Boolean $dry_run_on_unknown = false, 25 | ) { 26 | # suid and sgid blacklists and whitelists 27 | # --------------------------------------- 28 | # don't change values in the system_blacklist/whitelist 29 | # adjust values for blacklist/whitelist instead, 30 | # they can override system_blacklist/whitelist 31 | 32 | # list of suid/sgid entries that must be removed 33 | $system_blacklist = [ 34 | # blacklist as provided by NSA 35 | '/usr/bin/rcp', '/usr/bin/rlogin', '/usr/bin/rsh', 36 | # sshd must not use host-based authentication (see ssh cookbook) 37 | '/usr/libexec/openssh/ssh-keysign', 38 | '/usr/lib/openssh/ssh-keysign', 39 | # misc others 40 | # not normally required for user 41 | '/sbin/netreport', 42 | # modify interfaces via functional accounts 43 | '/usr/sbin/usernetctl', 44 | # connecting to ... 45 | # no isdn... 46 | '/usr/sbin/userisdnctl', 47 | # no ppp / dsl ... 48 | '/usr/sbin/pppd', 49 | # lockfile 50 | '/usr/bin/lockfile', 51 | '/usr/bin/mail-lock', 52 | '/usr/bin/mail-unlock', 53 | '/usr/bin/mail-touchlock', 54 | '/usr/bin/dotlockfile', 55 | # need more investigation, blacklist for now 56 | '/usr/bin/arping', 57 | '/usr/sbin/uuidd', 58 | # investigate current state... 59 | '/usr/bin/mtr', 60 | # investigate current state... 61 | '/usr/lib/evolution/camel-lock-helper-1.2', 62 | # pseudo-tty, needed? 63 | '/usr/lib/pt_chown', 64 | '/usr/lib/eject/dmcrypt-get-device', 65 | # midnight commander screensaver 66 | '/usr/lib/mc/cons.saver', 67 | ] 68 | 69 | # list of suid/sgid entries that can remain untouched 70 | $system_whitelist = [ 71 | # whitelist as provided by NSA 72 | '/bin/mount', '/bin/ping', '/bin/su', '/bin/umount', 73 | '/sbin/pam_timestamp_check','/sbin/unix_chkpwd', '/usr/bin/at', 74 | '/usr/bin/gpasswd', '/usr/bin/locate', '/usr/bin/newgrp', 75 | '/usr/bin/passwd', '/usr/bin/ssh-agent', '/usr/libexec/utempter/utempter', 76 | '/usr/sbin/lockdev', '/usr/sbin/sendmail.sendmail', '/usr/bin/expiry', 77 | # whitelist ipv6 78 | '/bin/ping6','/usr/bin/traceroute6.iputils', 79 | # whitelist nfs 80 | '/sbin/mount.nfs', '/sbin/umount.nfs', 81 | # whitelist nfs4 82 | '/sbin/mount.nfs4', '/sbin/umount.nfs4', 83 | # whitelist cron 84 | '/usr/bin/crontab', 85 | # whitelist consolemssaging 86 | '/usr/bin/wall', '/usr/bin/write', 87 | # whitelist: only SGID with utmp group for multi-session access 88 | # impact is limited; installation/usage has some remaining risk 89 | '/usr/bin/screen', 90 | # whitelist locate 91 | '/usr/bin/mlocate', 92 | # whitelist usermanagement 93 | '/usr/bin/chage', '/usr/bin/chfn', '/usr/bin/chsh', 94 | # whitelist fuse 95 | '/bin/fusermount', 96 | # whitelist pkexec 97 | '/usr/bin/pkexec', 98 | # whitelist sudo 99 | '/usr/bin/sudo','/usr/bin/sudoedit', 100 | # whitelist postfix 101 | '/usr/sbin/postdrop','/usr/sbin/postqueue', 102 | # whitelist apache 103 | '/usr/sbin/suexec', 104 | # whitelist squid 105 | '/usr/lib/squid/ncsa_auth', '/usr/lib/squid/pam_auth', 106 | # whitelist kerberos 107 | '/usr/kerberos/bin/ksu', 108 | # whitelist pam_caching 109 | '/usr/sbin/ccreds_validate', 110 | # whitelist Xorg 111 | '/usr/bin/Xorg', 112 | '/usr/bin/X', 113 | # freedesktop ipc 114 | '/usr/lib/dbus-1.0/dbus-daemon-launch-helper', 115 | # gnome 116 | '/usr/lib/vte/gnome-pty-helper', 117 | '/usr/lib/libvte9/gnome-pty-helper', 118 | '/usr/lib/libvte-2.90-9/gnome-pty-helper', 119 | ] 120 | 121 | $final_blacklist = combine_sugid_lists($system_blacklist, $whitelist, $blacklist) 122 | $final_whitelist = combine_sugid_lists($system_whitelist, $blacklist, $whitelist) 123 | 124 | os_hardening::blacklist_files { $final_blacklist: } 125 | 126 | if $remove_from_unknown { 127 | # create a helper script 128 | # TODO: do without 129 | file { '/usr/local/sbin/remove_suids': 130 | ensure => file, 131 | owner => 'root', 132 | group => 'root', 133 | mode => '0500', 134 | content => template('os_hardening/remove_sugid_bits.erb'), 135 | } 136 | #remove all bits 137 | exec { 'remove SUID/SGID bits from unknown': 138 | command => '/usr/local/sbin/remove_suids', 139 | } 140 | File['/usr/local/sbin/remove_suids'] -> Exec['remove SUID/SGID bits from unknown'] 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /manifests/sysctl.pp: -------------------------------------------------------------------------------- 1 | # === Copyright 2 | # 3 | # Copyright 2014, Deutsche Telekom AG 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | 8 | # == Class: os_hardening::sysctl 9 | # 10 | # Configures Kernel Parameters via sysctl 11 | # 12 | # @param enable_module_loading 13 | # 14 | # @param load_modules 15 | # 16 | # @param cpu_vendor 17 | # 18 | # @param icmp_ratelimit 19 | # 20 | # @param desktop_enabled 21 | # 22 | # @param enable_ipv4_forwarding 23 | # 24 | # @param manage_ipv6 25 | # 26 | # @param enable_ipv6 27 | # 28 | # @param enable_ipv6_forwarding 29 | # 30 | # @param arp_restricted 31 | # 32 | # @param arp_ignore_samenet 33 | # 34 | # @param enable_sysrq 35 | # 36 | # @param enable_core_dump 37 | # 38 | # @param enable_stack_protection 39 | # 40 | # @param enable_rpfilter 41 | # 42 | # @param rpfilter_loose 43 | # 44 | # @param enable_log_martians 45 | # 46 | class os_hardening::sysctl ( 47 | Boolean $enable_module_loading = true, 48 | Array $load_modules = [], 49 | String $cpu_vendor = 'intel', 50 | String $icmp_ratelimit = '100', 51 | Boolean $desktop_enabled = false, 52 | Boolean $enable_ipv4_forwarding = false, 53 | Boolean $manage_ipv6 = true, 54 | Boolean $enable_ipv6 = false, 55 | Boolean $enable_ipv6_forwarding = false, 56 | Boolean $arp_restricted = true, 57 | Boolean $arp_ignore_samenet = false, 58 | Boolean $enable_sysrq = false, 59 | Boolean $enable_core_dump = false, 60 | Boolean $enable_stack_protection = true, 61 | Boolean $enable_rpfilter = true, 62 | Boolean $rpfilter_loose = false, 63 | Boolean $enable_log_martians = true, 64 | ) { 65 | # set variables 66 | if $facts['os']['architecture'] == 'amd64' or $facts['os']['architecture'] == 'x86_64' { 67 | $x86_64 = true 68 | } else { 69 | $x86_64 = false 70 | } 71 | 72 | # configure sysctl parameters 73 | 74 | # Networking 75 | # ---------- 76 | 77 | # Only enable IP traffic forwarding, if required. 78 | sysctl { 'net.ipv4.ip_forward': value => String(bool2num($enable_ipv4_forwarding)) } 79 | 80 | # IPv6 enabled 81 | if $manage_ipv6 { 82 | if $enable_ipv6 { 83 | sysctl { 'net.ipv6.conf.all.disable_ipv6': value => '0' } 84 | sysctl { 'net.ipv6.conf.all.forwarding': value => String(bool2num($enable_ipv6_forwarding)) } 85 | } else { 86 | # IPv6 disabled 87 | sysctl { 'net.ipv6.conf.all.disable_ipv6': value => '1' } 88 | sysctl { 'net.ipv6.conf.all.forwarding': value => '0' } 89 | sysctl { 'net.ipv6.conf.default.router_solicitations': value => '0' } 90 | sysctl { 'net.ipv6.conf.default.accept_ra_rtr_pref': value => '0' } 91 | sysctl { 'net.ipv6.conf.default.accept_ra_pinfo': value => '0' } 92 | sysctl { 'net.ipv6.conf.default.accept_ra_defrtr': value => '0' } 93 | sysctl { 'net.ipv6.conf.default.autoconf': value => '0' } 94 | sysctl { 'net.ipv6.conf.default.dad_transmits': value => '0' } 95 | sysctl { 'net.ipv6.conf.default.max_addresses': value => '1' } 96 | } 97 | #ignore RAs on Ipv6 98 | sysctl { 'net.ipv6.conf.all.accept_ra': value => '0' } 99 | sysctl { 'net.ipv6.conf.default.accept_ra': value => '0' } 100 | } 101 | # Enable RFC-recommended source validation feature. It should not be used for routers on complex networks, but is helpful for 102 | # end hosts and routers serving small networks. 103 | if $enable_rpfilter { 104 | if $rpfilter_loose { 105 | $rpfilter = '2' 106 | } else { 107 | $rpfilter = '1' 108 | } 109 | } else { 110 | $rpfilter = '0' 111 | } 112 | sysctl { 'net.ipv4.conf.all.rp_filter': value => $rpfilter } 113 | sysctl { 'net.ipv4.conf.default.rp_filter': value => $rpfilter } 114 | 115 | # Reduce the surface on SMURF attacks. Make sure to ignore ECHO broadcasts, which are only required in broad network analysis. 116 | sysctl { 'net.ipv4.icmp_echo_ignore_broadcasts': value => '1' } 117 | 118 | # There is no reason to accept bogus error responses from ICMP, so ignore them instead. 119 | sysctl { 'net.ipv4.icmp_ignore_bogus_error_responses': value => '1' } 120 | 121 | # Limit the amount of traffic the system uses for ICMP. 122 | sysctl { 'net.ipv4.icmp_ratelimit': value => $icmp_ratelimit } 123 | 124 | # Adjust the ICMP ratelimit to include: ping, dst unreachable, source quench, time exceed, param problem, timestamp reply, 125 | # information reply 126 | sysctl { 'net.ipv4.icmp_ratemask': value => '88089' } 127 | 128 | # Protect against wrapping sequence numbers at gigabit speeds: 129 | sysctl { 'net.ipv4.tcp_timestamps': value => '0' } 130 | 131 | # arp_announce - INTEGER 132 | # Define different restriction levels for announcing the local source IP address from IP packets in ARP requests sent on interface: 133 | # 134 | # * **0** - (default) Use any local address, configured on any interface 135 | # * **1** - Try to avoid local addresses that are not in the target's subnet for this interface. This mode is useful when target 136 | # hosts reachable via this interface require the source IP address in ARP requests to be part of their logical network configured 137 | # on the receiving interface. When we generate the request we will check all our subnets that include the target IP and will 138 | # preserve the source address if it is from such subnet. If there is no such subnet we select source address according to the rules 139 | # for level 2. 140 | # * **2** - Always use the best local address for this target. In this mode we ignore the source address in the IP packet and try 141 | # to select local address that we prefer for talks with the target host. Such local address is selected by looking for primary IP 142 | # addresses on all our subnets on the outgoing interface that include the target IP address. If no suitable local address is found 143 | # we select the first local address we have on the outgoing interface or on all other interfaces, with the hope we will receive 144 | # reply for our request and even sometimes no matter the source IP address we announce. 145 | if $arp_restricted { 146 | if $arp_ignore_samenet { 147 | sysctl { 'net.ipv4.conf.all.arp_ignore': value => '2' } 148 | } else { 149 | sysctl { 'net.ipv4.conf.all.arp_ignore': value => '1' } 150 | } 151 | } else { 152 | sysctl { 'net.ipv4.conf.all.arp_ignore': value => '0' } 153 | } 154 | 155 | # Define different modes for sending replies in response to received ARP requests that resolve local target IP addresses: 156 | # 157 | # * **0** - (default): reply for any local target IP address, configured on any interface 158 | # * **1** - reply only if the target IP address is local address configured on the incoming interface 159 | # * **2** - reply only if the target IP address is local address configured on the incoming interface and both with the sender's 160 | # IP address are part from same subnet on this interface 161 | # * **3** - do not reply for local addresses configured with scope host, only resolutions for global and link addresses are replied 162 | # * **4-7** - reserved 163 | # * **8** - do not reply for all local addresses 164 | if $arp_restricted { 165 | sysctl { 'net.ipv4.conf.all.arp_announce': value => '2' } 166 | } else { 167 | sysctl { 'net.ipv4.conf.all.arp_announce': value => '0' } 168 | } 169 | 170 | # RFC 1337 fix F1 171 | sysctl { 'net.ipv4.tcp_rfc1337': value => '1' } 172 | 173 | # Syncookies is used to prevent SYN-flooding attacks. 174 | sysctl { 'net.ipv4.tcp_syncookies': value => '1' } 175 | 176 | sysctl { 'net.ipv4.conf.all.shared_media': value => '1' } 177 | sysctl { 'net.ipv4.conf.default.shared_media': value => '1' } 178 | 179 | # Accepting source route can lead to malicious networking behavior, so disable it if not needed. 180 | sysctl { 'net.ipv4.conf.all.accept_source_route': value => '0' } 181 | sysctl { 'net.ipv4.conf.default.accept_source_route': value => '0' } 182 | if $manage_ipv6 { 183 | sysctl { 'net.ipv6.conf.all.accept_source_route': value => '0' } 184 | sysctl { 'net.ipv6.conf.default.accept_source_route': value => '0' } 185 | } 186 | # Accepting redirects can lead to malicious networking behavior, so disable it if not needed. 187 | sysctl { 'net.ipv4.conf.all.accept_redirects': value => '0' } 188 | sysctl { 'net.ipv4.conf.default.accept_redirects': value => '0' } 189 | sysctl { 'net.ipv4.conf.all.secure_redirects': value => '0' } 190 | sysctl { 'net.ipv4.conf.default.secure_redirects': value => '0' } 191 | if $manage_ipv6 { 192 | sysctl { 'net.ipv6.conf.all.accept_redirects': value => '0' } 193 | sysctl { 'net.ipv6.conf.default.accept_redirects': value => '0' } 194 | } 195 | # For non-routers: don't send redirects, these settings are 0 196 | sysctl { 'net.ipv4.conf.all.send_redirects': value => '0' } 197 | sysctl { 'net.ipv4.conf.default.send_redirects': value => '0' } 198 | 199 | # log martian packets (risky, may cause DoS) 200 | sysctl { 'net.ipv4.conf.all.log_martians': value => String(bool2num($enable_log_martians)) } 201 | sysctl { 'net.ipv4.conf.default.log_martians': value => String(bool2num($enable_log_martians)) } 202 | 203 | # System 204 | # ------ 205 | 206 | # This settings controls how the kernel behaves towards module changes at runtime. Setting to 1 will disable module loading at runtime. 207 | if $enable_module_loading == false { 208 | sysctl { 'kernel.modules_disabled': value => '1' } 209 | } 210 | #kernel.modules_disabled = <%= @enable_module_loading ? 0 : 1 %> 211 | 212 | # Magic Sysrq should be disabled, but can also be set to a safe value if so desired for physical machines. It can allow a safe reboot if 213 | # the system hangs and is a 'cleaner' alternative to hitting the reset button. 214 | # The following values are permitted: 215 | # 216 | # * **0** - disable sysrq 217 | # * **1** - enable sysrq completely 218 | # * **>1** - bitmask of enabled sysrq functions: 219 | # * **2** - control of console logging level 220 | # * **4** - control of keyboard (SAK, unraw) 221 | # * **8** - debugging dumps of processes etc. 222 | # * **16** - sync command 223 | # * **32** - remount read-only 224 | # * **64** - signalling of processes (term, kill, oom-kill) 225 | # * **128** - reboot/poweroff 226 | # * **256** - nicing of all RT tasks 227 | if $enable_sysrq { 228 | $limited_sysrq = String(4 + 16 + 32 + 64 + 128) 229 | sysctl { 'kernel.sysrq': value => $limited_sysrq } 230 | } else { 231 | sysctl { 'kernel.sysrq': value => '0' } 232 | } 233 | 234 | # Enable stack protection by randomizing kernel va space 235 | if $enable_stack_protection { 236 | sysctl { 'kernel.randomize_va_space': value => '2' } 237 | } else { 238 | sysctl { 'kernel.randomize_va_space': value => '0' } 239 | } 240 | # Prevent core dumps with SUID. These are usually only needed by developers and may contain sensitive information. 241 | sysctl { 'fs.suid_dumpable': value => String(bool2num($enable_core_dump)) } 242 | 243 | # configure for module hardening 244 | # if modules cannot be loaded at runtime, they must all 245 | # be pre-configured in initramfs 246 | if $enable_module_loading == false { 247 | case $facts['os']['name'] { 248 | 'debian', 'ubuntu', 'cumuluslinux': { 249 | file { '/etc/initramfs-tools/modules': 250 | ensure => file, 251 | content => template('os_hardening/modules.erb'), 252 | owner => 'root', 253 | group => 'root', 254 | mode => '0400', 255 | notify => Exec['update-initramfs'], 256 | } 257 | 258 | exec { 'update-initramfs': 259 | command => '/usr/sbin/update-initramfs -u', 260 | refreshonly => true, 261 | } 262 | } 263 | default: { 264 | # TODO 265 | } 266 | } 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /manifests/umask.pp: -------------------------------------------------------------------------------- 1 | # === Copyright 2 | # 3 | # Copyright 2014, Deutsche Telekom AG 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | 8 | # == Class: os_hardening::umask 9 | # 10 | # Configures system umask. 11 | # 12 | # @param system_umask 13 | # 14 | class os_hardening::umask ( 15 | Optional[String] $system_umask = undef, 16 | ) { 17 | if $system_umask != undef { 18 | file { '/etc/profile.d/umask.sh': 19 | ensure => file, 20 | content => template('os_hardening/umask.sh.erb'), 21 | owner => 'root', 22 | group => 'root', 23 | mode => '0644', 24 | } 25 | } 26 | else { 27 | file { '/etc/profile.d/umask.sh': 28 | ensure => absent, 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardening-os_hardening", 3 | "version": "2.4.0", 4 | "author": "Dominik Richter", 5 | "summary": "Configures the base OS with hardening", 6 | "license": "Apache-2.0", 7 | "source": "https://github.com/dev-sec/puppet-os-hardening.git", 8 | "project_page": "https://github.com/dev-sec/puppet-os-hardening", 9 | "issues_url": "https://github.com/dev-sec/puppet-os-hardening/issues", 10 | "dependencies": [ 11 | { 12 | "name": "puppetlabs/stdlib", 13 | "version_requirement": ">= 4.6.0 < 10.0.0" 14 | }, 15 | { 16 | "name": "puppet-augeasproviders_sysctl", 17 | "version_requirement": ">= 2.2.1 < 4.0.0" 18 | } 19 | ], 20 | "operatingsystem_support": [ 21 | { 22 | "operatingsystem": "OracleLinux", 23 | "operatingsystemrelease": [ 24 | "7" 25 | ] 26 | }, 27 | { 28 | "operatingsystem": "CentOS", 29 | "operatingsystemrelease": [ 30 | "7", 31 | "8" 32 | ] 33 | }, 34 | { 35 | "operatingsystem": "OpenSuSE", 36 | "operatingsystemrelease": [ 37 | "15", 38 | "42" 39 | ] 40 | }, 41 | { 42 | "operatingsystem": "RedHat", 43 | "operatingsystemrelease": [ 44 | "7" 45 | ] 46 | }, 47 | { 48 | "operatingsystem": "Debian", 49 | "operatingsystemrelease": [ 50 | "7", 51 | "8", 52 | "9", 53 | "10" 54 | ] 55 | }, 56 | { 57 | "operatingsystem": "SLES", 58 | "operatingsystemrelease": [ 59 | "11", 60 | "12", 61 | "15" 62 | ] 63 | }, 64 | { 65 | "operatingsystem": "Ubuntu", 66 | "operatingsystemrelease": [ 67 | "14", 68 | "16", 69 | "18", 70 | "20" 71 | ] 72 | }, 73 | { 74 | "operatingsystem": "CumulusLinux", 75 | "operatingsystemrelease": [ 76 | "3", 77 | "4" 78 | ] 79 | } 80 | ], 81 | "requirements": [ 82 | { 83 | "name": "puppet", 84 | "version_requirement": ">= 6.0.0 < 9.0.0" 85 | } 86 | ], 87 | "template-url": "https://github.com/dev-sec/puppet-pdk-template#2.3.0", 88 | "pdk-version": "2.3.0", 89 | "template-ref": "tags/2.3.0-0-g8aaceff" 90 | } 91 | -------------------------------------------------------------------------------- /pdk.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | ignore: [] 3 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base", 5 | ":gitSignOff" 6 | ], 7 | "dependencyDashboard": true, 8 | "dependencyDashboardAutoclose": true, 9 | "packageRules": [ 10 | { 11 | "matchUpdateTypes": ["patch", "minor"], 12 | "automerge": true 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /spec/classes/os_hardening_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'os_hardening' do 4 | on_supported_os.each do |os, os_facts| 5 | context "on #{os}" do 6 | let(:facts) { os_facts } 7 | 8 | it { is_expected.to compile } 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/classes/sysctl_spec.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014, Deutsche Telekom AG 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | require 'spec_helper' 18 | 19 | describe 'os_hardening::sysctl' do 20 | on_supported_os.each do |os, os_facts| 21 | context "on #{os}" do 22 | let(:facts) { os_facts } 23 | 24 | it do 25 | is_expected.to contain_class('os_hardening::sysctl') 26 | end 27 | 28 | context 'with enable_ipv4_forwarding => true' do 29 | let(:params) { { enable_ipv4_forwarding: true } } 30 | 31 | it do 32 | is_expected.to contain_sysctl('net.ipv4.ip_forward').with_value('1') 33 | end 34 | end 35 | 36 | context 'with enable_ipv4_forwarding => false' do 37 | let(:params) { { enable_ipv4_forwarding: false } } 38 | 39 | it do 40 | is_expected.to contain_sysctl('net.ipv4.ip_forward').with_value('0') 41 | end 42 | end 43 | 44 | context 'with enable_ipv6 => true' do 45 | let(:params) { { enable_ipv6: true } } 46 | 47 | it do 48 | is_expected.to contain_sysctl('net.ipv6.conf.all.disable_ipv6').with_value('0') 49 | is_expected.to contain_sysctl('net.ipv6.conf.all.forwarding').with_value('0') 50 | end 51 | end 52 | 53 | context 'with enable_ipv6 => false' do 54 | let(:params) { { enable_ipv6: false } } 55 | 56 | it do 57 | is_expected.to contain_sysctl('net.ipv6.conf.all.disable_ipv6').with_value('1') 58 | is_expected.to contain_sysctl('net.ipv6.conf.all.forwarding').with_value('0') 59 | is_expected.to contain_sysctl('net.ipv6.conf.default.router_solicitations').with_value('0') 60 | is_expected.to contain_sysctl('net.ipv6.conf.default.accept_ra_rtr_pref').with_value('0') 61 | is_expected.to contain_sysctl('net.ipv6.conf.default.accept_ra_pinfo').with_value('0') 62 | is_expected.to contain_sysctl('net.ipv6.conf.default.accept_ra_defrtr').with_value('0') 63 | is_expected.to contain_sysctl('net.ipv6.conf.default.autoconf').with_value('0') 64 | is_expected.to contain_sysctl('net.ipv6.conf.default.dad_transmits').with_value('0') 65 | is_expected.to contain_sysctl('net.ipv6.conf.default.max_addresses').with_value('1') 66 | end 67 | end 68 | 69 | context 'with enable_ipv6_forwarding => true' do 70 | let(:params) { { enable_ipv6_forwarding: true, enable_ipv6: true } } 71 | 72 | it do 73 | is_expected.to contain_sysctl('net.ipv6.conf.all.forwarding').with_value('1') 74 | end 75 | end 76 | 77 | context 'with enable_ipv6_forwarding => false' do 78 | let(:params) { { enable_ipv6_forwarding: false, enable_ipv6: true } } 79 | 80 | it do 81 | is_expected.to contain_sysctl('net.ipv6.conf.all.forwarding').with_value('0') 82 | end 83 | end 84 | 85 | context 'with arp_restricted => true' do 86 | let(:params) { { arp_restricted: true } } 87 | 88 | it do 89 | is_expected.to contain_sysctl('net.ipv4.conf.all.arp_ignore').with_value('1') 90 | is_expected.to contain_sysctl('net.ipv4.conf.all.arp_announce').with_value('2') 91 | end 92 | end 93 | 94 | context 'with arp_restricted => false' do 95 | let(:params) { { arp_restricted: false } } 96 | 97 | it do 98 | is_expected.to contain_sysctl('net.ipv4.conf.all.arp_ignore').with_value('0') 99 | is_expected.to contain_sysctl('net.ipv4.conf.all.arp_announce').with_value('0') 100 | end 101 | end 102 | 103 | context 'with enable_module_loading => true' do 104 | let(:params) { { enable_module_loading: true } } 105 | 106 | it do 107 | is_expected.not_to contain_sysctl('kernel.modules_disabled') 108 | end 109 | end 110 | 111 | context 'with enable_module_loading => false' do 112 | let(:params) { { enable_module_loading: false } } 113 | 114 | it do 115 | is_expected.to contain_sysctl('kernel.modules_disabled').with_value('1') 116 | end 117 | end 118 | 119 | context 'with enable_sysrq => true' do 120 | let(:params) { { enable_sysrq: true } } 121 | 122 | it do 123 | allowed_sysrq = 4 + 16 + 32 + 64 + 128 124 | is_expected.to contain_sysctl('kernel.sysrq').with_value(allowed_sysrq) 125 | end 126 | end 127 | 128 | context 'with enable_sysrq => false' do 129 | let(:params) { { enable_sysrq: false } } 130 | 131 | it do 132 | is_expected.to contain_sysctl('kernel.sysrq').with_value('0') 133 | end 134 | end 135 | 136 | context 'with enable_stack_protection => true' do 137 | let(:params) { { enable_stack_protection: true } } 138 | 139 | it do 140 | is_expected.to contain_sysctl('kernel.randomize_va_space').with_value('2') 141 | end 142 | end 143 | 144 | context 'with enable_stack_protection => false' do 145 | let(:params) { { enable_stack_protection: false } } 146 | 147 | it do 148 | is_expected.to contain_sysctl('kernel.randomize_va_space').with_value('0') 149 | end 150 | end 151 | 152 | context 'with enable_core_dump => true' do 153 | let(:params) { { enable_core_dump: true } } 154 | 155 | it do 156 | is_expected.to contain_sysctl('fs.suid_dumpable').with_value('1') 157 | end 158 | end 159 | 160 | context 'with enable_core_dump => false' do 161 | let(:params) { { enable_core_dump: false } } 162 | 163 | it do 164 | is_expected.to contain_sysctl('fs.suid_dumpable').with_value('0') 165 | end 166 | end 167 | 168 | context 'with icmp_ratelimit => 10' do 169 | let(:params) { { icmp_ratelimit: '10' } } 170 | 171 | it do 172 | is_expected.to contain_sysctl('net.ipv4.icmp_ratelimit').with_value('10') 173 | end 174 | end 175 | end 176 | end 177 | end 178 | -------------------------------------------------------------------------------- /spec/default_facts.yml: -------------------------------------------------------------------------------- 1 | # Use default_module_facts.yml for module specific facts. 2 | # 3 | # Facts specified here will override the values provided by rspec-puppet-facts. 4 | --- 5 | ipaddress: "172.16.254.254" 6 | ipaddress6: "FE80:0000:0000:0000:AAAA:AAAA:AAAA" 7 | is_pe: false 8 | macaddress: "AA:AA:AA:AA:AA:AA" 9 | retrieve_system_users: root,bin,daemon,adm,lp,sync,shutdown,halt,mail,operator,games,ftp,nobody,systemd-network,dbus,polkitd,rpc,rpcuser,postfix,sshd,chrony 10 | home_users: '' 11 | 12 | -------------------------------------------------------------------------------- /spec/fixtures/etc/login.defs: -------------------------------------------------------------------------------- 1 | # 2 | # Please note that the parameters in this configuration file control the 3 | # behavior of the tools from the shadow-utils component. None of these 4 | # tools uses the PAM mechanism, and the utilities that use PAM (such as the 5 | # passwd command) should therefore be configured elsewhere. Refer to 6 | # /etc/pam.d/system-auth for more information. 7 | # 8 | 9 | # *REQUIRED* 10 | # Directory where mailboxes reside, _or_ name of file, relative to the 11 | # home directory. If you _do_ define both, MAIL_DIR takes precedence. 12 | # QMAIL_DIR is for Qmail 13 | # 14 | #QMAIL_DIR Maildir 15 | MAIL_DIR /var/spool/mail 16 | #MAIL_FILE .mail 17 | 18 | # Password aging controls: 19 | # 20 | # PASS_MAX_DAYS Maximum number of days a password may be used. 21 | # PASS_MIN_DAYS Minimum number of days allowed between password changes. 22 | # PASS_MIN_LEN Minimum acceptable password length. 23 | # PASS_WARN_AGE Number of days warning given before a password expires. 24 | # 25 | PASS_MAX_DAYS 99999 26 | PASS_MIN_DAYS 0 27 | PASS_MIN_LEN 5 28 | PASS_WARN_AGE 7 29 | 30 | # 31 | # Min/max values for automatic uid selection in useradd 32 | # 33 | UID_MIN 1000 34 | UID_MAX 60000 35 | # System accounts 36 | SYS_UID_MIN 201 37 | SYS_UID_MAX 999 38 | 39 | # 40 | # Min/max values for automatic gid selection in groupadd 41 | # 42 | GID_MIN 1000 43 | GID_MAX 60000 44 | # System accounts 45 | SYS_GID_MIN 201 46 | SYS_GID_MAX 999 47 | 48 | # 49 | # If defined, this command is run when removing a user. 50 | # It should remove any at/cron/print jobs etc. owned by 51 | # the user to be removed (passed as the first argument). 52 | # 53 | #USERDEL_CMD /usr/sbin/userdel_local 54 | 55 | # 56 | # If useradd should create home directories for users by default 57 | # On RH systems, we do. This option is overridden with the -m flag on 58 | # useradd command line. 59 | # 60 | CREATE_HOME yes 61 | 62 | # The permission mask is initialized to this value. If not specified, 63 | # the permission mask will be initialized to 022. 64 | UMASK 077 65 | 66 | # This enables userdel to remove user groups if no members exist. 67 | # 68 | USERGROUPS_ENAB yes 69 | 70 | # Use SHA512 to encrypt password. 71 | ENCRYPT_METHOD MD5 72 | 73 | MD5_CRYPT_ENAB yes 74 | -------------------------------------------------------------------------------- /spec/functions/combine_sugid_lists_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'combine_sugid_lists' do 4 | it { is_expected.not_to eq(nil) } 5 | it { is_expected.to run.with_params.and_raise_error(ArgumentError) } 6 | it { is_expected.to run.with_params('one', 'two', 'three').and_raise_error(ArgumentError) } 7 | it { is_expected.to run.with_params(%w[one two], %w[one two]).and_raise_error(ArgumentError) } 8 | it { is_expected.to run.with_params(%w[one two three], %w[three], %w[four five]).and_return(%w[one two four five]) } 9 | end 10 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.configure do |c| 4 | c.mock_with :rspec 5 | end 6 | 7 | require 'puppetlabs_spec_helper/module_spec_helper' 8 | require 'rspec-puppet-facts' 9 | 10 | require 'spec_helper_local' if File.file?(File.join(File.dirname(__FILE__), 'spec_helper_local.rb')) 11 | 12 | include RspecPuppetFacts 13 | 14 | default_facts = { 15 | puppetversion: Puppet.version, 16 | facterversion: Facter.version, 17 | } 18 | 19 | default_fact_files = [ 20 | File.expand_path(File.join(File.dirname(__FILE__), 'default_facts.yml')), 21 | File.expand_path(File.join(File.dirname(__FILE__), 'default_module_facts.yml')), 22 | ] 23 | 24 | default_fact_files.each do |f| 25 | next unless File.exist?(f) && File.readable?(f) && File.size?(f) 26 | 27 | begin 28 | default_facts.merge!(YAML.safe_load(File.read(f), [], [], true)) 29 | rescue => e 30 | RSpec.configuration.reporter.message "WARNING: Unable to load #{f}: #{e}" 31 | end 32 | end 33 | 34 | # read default_facts and merge them over what is provided by facterdb 35 | default_facts.each do |fact, value| 36 | add_custom_fact fact, value 37 | end 38 | 39 | RSpec.configure do |c| 40 | c.default_facts = default_facts 41 | c.before :each do 42 | # set to strictest setting for testing 43 | # by default Puppet runs at warning level 44 | Puppet.settings[:strict] = :warning 45 | Puppet.settings[:strict_variables] = true 46 | end 47 | c.filter_run_excluding(bolt: true) unless ENV['GEM_BOLT'] 48 | c.after(:suite) do 49 | end 50 | 51 | # Filter backtrace noise 52 | backtrace_exclusion_patterns = [ 53 | %r{spec_helper}, 54 | %r{gems}, 55 | ] 56 | 57 | if c.respond_to?(:backtrace_exclusion_patterns) 58 | c.backtrace_exclusion_patterns = backtrace_exclusion_patterns 59 | elsif c.respond_to?(:backtrace_clean_patterns) 60 | c.backtrace_clean_patterns = backtrace_exclusion_patterns 61 | end 62 | end 63 | 64 | # Ensures that a module is defined 65 | # @param module_name Name of the module 66 | def ensure_module_defined(module_name) 67 | module_name.split('::').reduce(Object) do |last_module, next_module| 68 | last_module.const_set(next_module, Module.new) unless last_module.const_defined?(next_module, false) 69 | last_module.const_get(next_module, false) 70 | end 71 | end 72 | 73 | # 'spec_overrides' from sync.yml will appear below this line 74 | -------------------------------------------------------------------------------- /spec/unit/facter/home_users_spec.rb: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env ruby -S rspec # rubocop:disable Lint/ScriptPermission : Rubocop error?? 2 | require 'spec_helper' 3 | 4 | describe 'home_users', type: :fact do 5 | before(:each) do 6 | Facter.clear 7 | allow(File).to receive(:readline) 8 | .with('/etc/login.defs') 9 | .and_return(IO.read("#{File.dirname(__FILE__)}/../../fixtures/etc/login.defs")) 10 | 11 | # https://ruby-doc.org/stdlib-2.5.3/libdoc/etc/rdoc/Struct.html#Passwd 12 | # fields: name, passwd, uid, gid, gecos, homedir, shell 13 | user_root = Etc::Passwd.new('root', 'x', 0, 0, 'root', '/root', '/bin/bash') 14 | user_bin = Etc::Passwd.new('bin', 'x', 1, 1, 'bin', '/bin', '/sbin/nologin') 15 | user_daemon = Etc::Passwd.new('daemon', 'x', 2, 2, 'daemon', '/sbin', '/sbin/nologin') 16 | user_testuser = Etc::Passwd.new('testuser', 'x', 1000, 1000, 'tesuser', '/home/testuser', '/bin/bash') 17 | 18 | allow(Etc).to receive(:passwd) 19 | .and_yield(user_root) 20 | .and_yield(user_bin) 21 | .and_yield(user_daemon) 22 | .and_yield(user_testuser) 23 | end 24 | after(:each) { Facter.clear } 25 | context 'on CentOS is should' do 26 | it 'have basic users set' do 27 | expect(Facter.fact(:home_users).value).to eq('/home/testuser') 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /spec/unit/facter/retrieve_system_users_spec.rb: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env ruby -S rspec # rubocop:disable Lint/ScriptPermission : Rubocop error?? 2 | require 'spec_helper' 3 | 4 | describe 'retrieve_system_users', type: :fact do 5 | before(:each) do 6 | Facter.clear 7 | allow(File).to receive(:readline) 8 | .with('/etc/login.defs') 9 | .and_return(IO.read("#{File.dirname(__FILE__)}/../../fixtures/etc/login.defs")) 10 | 11 | # https://ruby-doc.org/stdlib-2.5.3/libdoc/etc/rdoc/Struct.html#Passwd 12 | # fields: name, passwd, uid, gid, gecos, homedir, shell 13 | user_root = Etc::Passwd.new('root', 'x', 0, 0, 'root', '/root', '/bin/bash') 14 | user_bin = Etc::Passwd.new('bin', 'x', 1, 1, 'bin', '/bin', '/sbin/nologin') 15 | user_daemon = Etc::Passwd.new('daemon', 'x', 2, 2, 'daemon', '/sbin', '/sbin/nologin') 16 | user_testuser = Etc::Passwd.new('testuser', 'x', 1000, 1000, 'tesuser', '/home/testuser', '/bin/bash') 17 | 18 | allow(Etc).to receive(:passwd) 19 | .and_yield(user_root) 20 | .and_yield(user_bin) 21 | .and_yield(user_daemon) 22 | .and_yield(user_testuser) 23 | end 24 | after(:each) { Facter.clear } 25 | context 'on CentOS is should' do 26 | it 'have basic users set' do 27 | expect(Facter.fact(:retrieve_system_users).value).to eq('root,bin,daemon') 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /templates/disable_fs.erb: -------------------------------------------------------------------------------- 1 | # MANAGED BY PUPPET 2 | # Puppet os_hardening: Disable filesystems (os-10) 3 | 4 | <% @disable_filesystems.each do |fs| -%> 5 | install <%= fs %> /bin/true 6 | <% end -%> 7 | 8 | -------------------------------------------------------------------------------- /templates/grub_hardening.erb: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # MANAGED BY PUPPET 3 | echo set superusers="<%= @user %>" 4 | echo password_pbkdf2 <%= @user %> <%= @password_hash %> 5 | 6 | -------------------------------------------------------------------------------- /templates/login.defs.erb: -------------------------------------------------------------------------------- 1 | # MANAGED BY PUPPET 2 | # Configuration control definitions for the login package. 3 | # 4 | # Three items must be defined: `MAIL_DIR`, `ENV_SUPATH`, and `ENV_PATH`. If unspecified, some arbitrary (and possibly incorrect) value will be assumed. All other items are optional - if not specified then the described action or option will be inhibited. 5 | # 6 | # Comment lines (lines beginning with `#`) and blank lines are ignored. 7 | # 8 | #-- Modified for Linux. --marekm 9 | 10 | # *REQUIRED for useradd/userdel/usermod* 11 | # 12 | # Directory where mailboxes reside, _or_ name of file, relative to the home directory. If you _do_ define `MAIL_DIR` and `MAIL_FILE`, `MAIL_DIR` takes precedence. 13 | # Essentially: 14 | # 15 | # * `MAIL_DIR` defines the location of users mail spool files (for mbox use) by appending the username to `MAIL_DIR` as defined below. 16 | # * `MAIL_FILE` defines the location of the users mail spool files as the fully-qualified filename obtained by prepending the user home directory before `$MAIL_FILE` 17 | # 18 | # *NOTE*: This is no more used for setting up users MAIL environment variable which is, starting from shadow 4.0.12-1 in Debian, entirely the job of the pam_mail PAM modules. 19 | # 20 | # See default PAM configuration files provided for login, su, etc. 21 | # This is a temporary situation: setting these variables will soon move to `/etc/default/useradd` and the variables will then be no more supported 22 | MAIL_DIR <%= @maildir %> 23 | #MAIL_FILE .mail 24 | 25 | # Enable logging and display of `/var/log/faillog` login failure info. This option conflicts with the `pam_tally` PAM module. 26 | FAILLOG_ENAB yes 27 | 28 | # Enable display of unknown usernames when login failures are recorded. 29 | # 30 | # *WARNING*: Unknown usernames may become world readable. See #290803 and #298773 for details about how this could become a security concern 31 | LOG_UNKFAIL_ENAB no 32 | 33 | # Enable logging of successful logins 34 | LOG_OK_LOGINS no 35 | 36 | # Enable "syslog" logging of su activity - in addition to sulog file logging. 37 | SYSLOG_SU_ENAB yes 38 | 39 | # Enable "syslog" logging of newgrp and sg. 40 | SYSLOG_SG_ENAB yes 41 | 42 | # If defined, all su activity is logged to this file. 43 | #SULOG_FILE /var/log/sulog 44 | 45 | # If defined, file which maps tty line to `TERM` environment parameter. Each line of the file is in a format something like "vt100 tty01". 46 | #TTYTYPE_FILE /etc/ttytype 47 | 48 | # If defined, login failures will be logged here in a utmp format last, when invoked as lastb, will read `/var/log/btmp`, so... 49 | FTMP_FILE /var/log/btmp 50 | 51 | # If defined, the command name to display when running "su -". For # example, if this is defined as "su" then a "ps" will display the command is "-su". If not defined, then "ps" would display the name of the shell actually being run, e.g. something like "-sh". 52 | SU_NAME su 53 | 54 | # If defined, file which inhibits all the usual chatter during the login sequence. If a full pathname, then hushed mode will be enabled if the user's name or shell are found in the file. If not a full pathname, then hushed mode will be enabled if the file exists in the user's home directory. 55 | #HUSHLOGIN_FILE /etc/hushlogins 56 | HUSHLOGIN_FILE .hushlogin 57 | 58 | # *REQUIRED*: The default PATH settings, for superuser and normal users. (they are minimal, add the rest in the shell startup files) 59 | ENV_SUPATH PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 60 | ENV_PATH PATH=/usr/local/bin:/usr/bin:/bin<% if not @additional_user_paths.empty? %>:<%= @additional_user_paths %><% end %> 61 | 62 | # Terminal permissions 63 | # -------------------- 64 | 65 | # Login tty will be assigned this group ownership. 66 | # If you have a "write" program which is "setgid" to a special group which owns the terminals, define `TTYGROUP` to the group number and `TTYPERM` to `0620`. Otherwise leave `TTYGROUP` commented out and assign `TTYPERM` to either `622` or `600`. 67 | TTYGROUP tty 68 | 69 | # Login tty will be set to this permission. 70 | # In Debian `/usr/bin/bsd-write` or similar programs are setgid tty. However, the default and recommended value for `TTYPERM` is still `0600` to not allow anyone to write to anyone else console or terminal 71 | # Users can still allow other people to write them by issuing the `mesg y` command. 72 | TTYPERM 0600 73 | 74 | # Login conf initializations 75 | # -------------------------- 76 | 77 | # Terminal ERASE character ('\010' = backspace). Only used on System V. 78 | ERASECHAR 0177 79 | 80 | # Terminal KILL character ('\025' = CTRL/U). Only used on System V. 81 | KILLCHAR 025 82 | 83 | # The default umask value for `pam_umask` and is used by useradd and newusers to set the mode of the new home directories. 84 | # If `USERGROUPS_ENAB` is set to `yes`, that will modify this `UMASK` default value for private user groups, i. e. the uid is the same as gid, and username is the same as the primary group name: for these, the user permissions will be used as group permissions, e. g. `022` will become `002`. 85 | # Prefix these values with `0` to get octal, `0x` to get hexadecimal. 86 | # `022` is the "historical" value in Debian for UMASK 87 | # `027`, or even `077`, could be considered better for privacy. 88 | UMASK <%= @umask %> 89 | 90 | # Enable setting of the umask group bits to be the same as owner bits (examples: `022` -> `002`, `077` -> `007`) for non-root users, if the uid is the same as gid, and username is the same as the primary group name. 91 | # If set to yes, userdel will remove the user's group if it contains no more members, and useradd will create by default a group with the name of the user. 92 | USERGROUPS_ENAB <%= @usergroups_yn %> 93 | 94 | 95 | # Password aging controls 96 | # ----------------------- 97 | 98 | # Maximum number of days a password may be used. 99 | PASS_MAX_DAYS <%= @password_max_age.to_s %> 100 | 101 | # Minimum number of days allowed between password changes. 102 | PASS_MIN_DAYS <%= @password_min_age.to_s %> 103 | 104 | # Number of days warning given before a password expires. 105 | PASS_WARN_AGE <%= @password_warn_age.to_s %> 106 | 107 | # Min/max values for automatic uid selection in useradd 108 | UID_MIN 1000 109 | UID_MAX 60000 110 | # System accounts 111 | SYS_UID_MIN <%= @sys_uid_min %> 112 | SYS_UID_MAX 999 113 | 114 | # Min/max values for automatic gid selection in groupadd 115 | GID_MIN 1000 116 | GID_MAX 60000 117 | # System accounts 118 | SYS_GID_MIN <%= @sys_gid_min %> 119 | SYS_GID_MAX 999 120 | 121 | # Max number of login retries if password is bad. This will most likely be overridden by PAM, since the default pam_unix module has it's own built in of 3 retries. However, this is a safe fallback in case you are using an authentication module that does not enforce PAM_MAXTRIES. 122 | LOGIN_RETRIES <%= @login_retries.to_s %> 123 | 124 | # Max time in seconds for login 125 | LOGIN_TIMEOUT <%= @login_timeout.to_s %> 126 | 127 | # Which fields may be changed by regular users using chfn - use any combination of letters "frwh" (full name, room number, work phone, home phone). If not defined, no changes are allowed. 128 | # For backward compatibility, "yes" = "rwh" and "no" = "frwh". 129 | <% if @chfn_restrict %> 130 | CHFN_RESTRICT <%= @chfn_restrict %> 131 | <% end %> 132 | 133 | # Should login be allowed if we can't cd to the home directory? 134 | DEFAULT_HOME <%= @allow_login_without_home ? "yes" : "no" %> 135 | 136 | # If defined, this command is run when removing a user. 137 | # It should remove any at/cron/print jobs etc. owned by 138 | # the user to be removed (passed as the first argument). 139 | #USERDEL_CMD /usr/sbin/userdel_local 140 | 141 | # Instead of the real user shell, the program specified by this parameter will be launched, although its visible name (`argv[0]`) will be the shell's. The program may do whatever it wants (logging, additional authentication, banner, ...) before running the actual shell. 142 | #FAKE_SHELL /bin/fakeshell 143 | 144 | # If defined, either full pathname of a file containing device names or a ":" delimited list of device names. Root logins will be allowed only upon these devices. 145 | # This variable is used by login and su. 146 | #CONSOLE /etc/consoles 147 | #CONSOLE console:tty01:tty02:tty03:tty04 148 | 149 | # List of groups to add to the user's supplementary group set when logging in on the console (as determined by the `CONSOLE` setting). Default is none. 150 | # Use with caution - it is possible for users to gain permanent access to these groups, even when not logged in on the console. How to do it is left as an exercise for the reader... 151 | # This variable is used by login and su. 152 | #CONSOLE_GROUPS floppy:audio:cdrom 153 | 154 | # If set to `MD5`, MD5-based algorithm will be used for encrypting password 155 | # If set to `SHA256`, SHA256-based algorithm will be used for encrypting password 156 | # If set to `SHA512`, SHA512-based algorithm will be used for encrypting password 157 | # If set to `DES`, DES-based algorithm will be used for encrypting password (default) 158 | # Overrides the MD5_CRYPT_ENAB option 159 | # 160 | # Note: It is recommended to use a value consistent with 161 | # the PAM modules configuration. 162 | MD5_CRYPT_ENAB no 163 | ENCRYPT_METHOD SHA512 164 | 165 | # Only used if `ENCRYPT_METHOD` is set to `SHA256` or `SHA512`: Define the number of SHA rounds. 166 | # With a lot of rounds, it is more difficult to brute forcing the password. But note also that it more CPU resources will be needed to authenticate users. 167 | # If not specified, the libc will choose the default number of rounds (5000). The values must be inside the 1000-999999999 range. If only one of the MIN or MAX values is set, then this value will be used. 168 | # If MIN > MAX, the highest value will be used. 169 | SHA_CRYPT_MIN_ROUNDS 640000 170 | SHA_CRYPT_MAX_ROUNDS 640000 171 | 172 | 173 | # Obsoleted by PAM 174 | # ================ 175 | # These options are now handled by PAM. Please edit the appropriate file in `/etc/pam.d/` to enable the equivalents of them. 176 | #MOTD_FILE 177 | #DIALUPS_CHECK_ENAB 178 | #LASTLOG_ENAB 179 | #MAIL_CHECK_ENAB 180 | #OBSCURE_CHECKS_ENAB 181 | #PORTTIME_CHECKS_ENAB 182 | #SU_WHEEL_ONLY 183 | #CRACKLIB_DICTPATH 184 | #PASS_CHANGE_TRIES 185 | #PASS_ALWAYS_WARN 186 | #ENVIRON_FILE 187 | #NOLOGINS_FILE 188 | #ISSUE_FILE 189 | #PASS_MIN_LEN 190 | #PASS_MAX_LEN 191 | #ULIMIT 192 | #ENV_HZ 193 | #CHFN_AUTH 194 | #CHSH_AUTH 195 | #FAIL_DELAY 196 | 197 | # Obsoleted 198 | # ========= 199 | # These options are no more handled by shadow. 200 | # Shadow utilities will display a warning if they still appear. 201 | #CLOSE_SESSIONS 202 | #LOGIN_STRING 203 | #NO_PASSWORD_CONSOLE 204 | #QMAIL_DIR 205 | 206 | # If set to `yes`, new passwords will be encrypted using the MD5-based algorithm compatible with the one used by recent releases of FreeBSD. It supports passwords of unlimited length and longer salt strings. 207 | # Set to `no` if you need to copy encrypted passwords to other systems which don't understand the new algorithm. Default is `no`. 208 | # This variable is deprecated. You should use ENCRYPT_METHOD. 209 | # 210 | #MD5_CRYPT_ENAB no 211 | 212 | -------------------------------------------------------------------------------- /templates/modules.erb: -------------------------------------------------------------------------------- 1 | # MANAGED BY PUPPET 2 | # This file contains the names of kernel modules that should be loaded at boot time, one per line. Lines beginning with "#" are ignored. 3 | # 4 | # A list of all available kernel modules kann be found with `find /lib/modules/$(uname -r)/kernel/` 5 | # We will sort by folder. 6 | 7 | 8 | # Arch 9 | # ---- 10 | # 11 | # Modules for certains builds, contains support modules and some CPU-specific optimizations. 12 | 13 | <% if @x86_64 == true %> 14 | # Optimize for x86_64 cryptographic features 15 | twofish-x86_64-3way 16 | twofish-x86_64 17 | aes-x86_64 18 | salsa20-x86_64 19 | blowfish-x86_64 20 | <% end %> 21 | 22 | <% if @cpu_vendor == "intel" %> 23 | # Intel-specific optimizations 24 | ghash-clmulni-intel 25 | aesni-intel 26 | kvm-intel 27 | <% end %> 28 | 29 | <% if @cpu_vendor == "amd" %> 30 | # AMD-specific optimizations 31 | kvm-amd 32 | <% end %> 33 | 34 | kvm 35 | 36 | 37 | # Crypto 38 | # ------ 39 | 40 | # Some core modules which comprise strong cryptography. 41 | blowfish_common 42 | blowfish_generic 43 | ctr 44 | cts 45 | lrw 46 | lzo 47 | rmd160 48 | rmd256 49 | rmd320 50 | serpent 51 | sha512_generic 52 | twofish_common 53 | twofish_generic 54 | xts 55 | zlib 56 | 57 | 58 | # Drivers 59 | # ------- 60 | 61 | # Basics 62 | lp 63 | rtc 64 | loop 65 | 66 | # Filesystems 67 | ext2 68 | btrfs 69 | 70 | <% if @desktop_enabled %> 71 | # Desktop 72 | psmouse 73 | snd 74 | snd_ac97_codec 75 | snd_intel8x0 76 | snd_page_alloc 77 | snd_pcm 78 | snd_timer 79 | soundcore 80 | usbhid 81 | <% end %> 82 | 83 | # Lib 84 | # --- 85 | xz 86 | 87 | 88 | # Net 89 | # --- 90 | 91 | # All packets needed for netfilter rules (ie iptables, ebtables). 92 | ip_tables 93 | x_tables 94 | iptable_filter 95 | iptable_nat 96 | 97 | # Targets 98 | ipt_LOG 99 | ipt_REJECT 100 | 101 | # Modules 102 | xt_connlimit 103 | xt_tcpudp 104 | xt_recent 105 | xt_limit 106 | xt_conntrack 107 | nf_conntrack 108 | nf_conntrack_ipv4 109 | nf_defrag_ipv4 110 | xt_state 111 | nf_nat 112 | 113 | # Addons 114 | xt_pknock 115 | 116 | # Load following requested modules 117 | <%= @load_modules.join("\n") %> 118 | -------------------------------------------------------------------------------- /templates/pam_passwdqc.erb: -------------------------------------------------------------------------------- 1 | # MANAGED BY PUPPET 2 | Name: passwdqc password strength enforcement 3 | Default: yes 4 | Priority: 1024 5 | Conflicts: cracklib 6 | Password-Type: Primary 7 | Password: 8 | requisite pam_passwdqc.so <%= @passwdqc_options %> 9 | -------------------------------------------------------------------------------- /templates/pam_su_debian_ubuntu.erb: -------------------------------------------------------------------------------- 1 | # MANAGED BY PUPPET 2 | # 3 | # The PAM configuration file for the Shadow `su' service 4 | # 5 | 6 | # This allows root to su without passwords (normal operation) 7 | auth sufficient pam_rootok.so 8 | # This allows members of group wheel to use su 9 | <% if @only_root_may_su %> 10 | auth required pam_wheel.so use_uid 11 | <% else %> 12 | # auth required pam_wheel.so use_uid 13 | <% end %> 14 | # Uncomment this to force users to be a member of group root 15 | # before they can use `su'. You can also add "group=foo" 16 | # to the end of this line if you want to use a group other 17 | # than the default "root" (but this may have side effect of 18 | # denying "root" user, unless she's a member of "foo" or explicitly 19 | # permitted earlier by e.g. "sufficient pam_rootok.so"). 20 | # (Replaces the `SU_WHEEL_ONLY' option from login.defs) 21 | # auth required pam_wheel.so 22 | 23 | # Uncomment this if you want wheel members to be able to 24 | # su without a password. 25 | # auth sufficient pam_wheel.so trust 26 | 27 | # Uncomment this if you want members of a specific group to not 28 | # be allowed to use su at all. 29 | # auth required pam_wheel.so deny group=nosu 30 | 31 | # Uncomment and edit /etc/security/time.conf if you need to set 32 | # time restrainst on su usage. 33 | # (Replaces the `PORTTIME_CHECKS_ENAB' option from login.defs 34 | # as well as /etc/porttime) 35 | # account requisite pam_time.so 36 | 37 | # This module parses environment configuration file(s) 38 | # and also allows you to use an extended config 39 | # file /etc/security/pam_env.conf. 40 | # 41 | # parsing /etc/environment needs "readenv=1" 42 | session required pam_env.so readenv=1 43 | # locale variables are also kept into /etc/default/locale in etch 44 | # reading this file *in addition to /etc/environment* does not hurt 45 | session required pam_env.so readenv=1 envfile=/etc/default/locale 46 | 47 | # Defines the MAIL environment variable 48 | # However, userdel also needs MAIL_DIR and MAIL_FILE variables 49 | # in /etc/login.defs to make sure that removing a user 50 | # also removes the user's mail spool file. 51 | # See comments in /etc/login.defs 52 | # 53 | # "nopen" stands to avoid reporting new mail when su'ing to another user 54 | session optional pam_mail.so nopen 55 | 56 | # Sets up user limits according to /etc/security/limits.conf 57 | # (Replaces the use of /etc/limits in old login) 58 | session required pam_limits.so 59 | 60 | # The standard Unix authentication modules, used with 61 | # NIS (man nsswitch) as well as normal /etc/passwd and 62 | # /etc/shadow entries. 63 | @include common-auth 64 | @include common-account 65 | @include common-session 66 | 67 | -------------------------------------------------------------------------------- /templates/pam_tally2.erb: -------------------------------------------------------------------------------- 1 | # MANAGED BY PUPPET 2 | Name: tally2 lockout after failed attempts enforcement 3 | Default: yes 4 | Priority: 1024 5 | Conflicts: cracklib 6 | Auth-Type: Primary 7 | Auth-Initial: 8 | required pam_tally2.so deny=<%= @auth_retries %> onerr=fail unlock_time=<%= @auth_lockout_time %> 9 | Account-Type: Primary 10 | Account-Initial: 11 | required pam_tally2.so 12 | -------------------------------------------------------------------------------- /templates/pam_unix.erb: -------------------------------------------------------------------------------- 1 | # MANAGED BY PUPPET 2 | Name: Unix authentication 3 | Default: yes 4 | Priority: 256 5 | Auth-Type: Primary 6 | Auth: 7 | [success=end default=ignore] pam_unix.so nullok_secure try_first_pass 8 | Auth-Initial: 9 | [success=end default=ignore] pam_unix.so nullok_secure 10 | Account-Type: Primary 11 | Account: 12 | [success=end new_authtok_reqd=done default=ignore] pam_unix.so 13 | Account-Initial: 14 | [success=end new_authtok_reqd=done default=ignore] pam_unix.so 15 | Session-Type: Additional 16 | Session: 17 | required pam_unix.so 18 | Session-Initial: 19 | required pam_unix.so 20 | Password-Type: Primary 21 | Password: 22 | [success=end default=ignore] pam_unix.so obscure use_authtok try_first_pass sha512 <%= @pw_history_options %> 23 | Password-Initial: 24 | [success=end default=ignore] pam_unix.so obscure sha512 25 | -------------------------------------------------------------------------------- /templates/remove_sugid_bits.erb: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # MANAGED BY PUPPET 3 | # Script to remove all not whitelisted SUIDs on all FS beside FSs mounted with nosuid 4 | # Artem Sidorenko , Dominik Richter 5 | # 2013-2014 Deutsche Telekom AG 6 | 7 | # suid whitelist 8 | suid_whitelist="<%= @final_whitelist.join('|') %>" 9 | 10 | #filesystems to check, we ignore mounts with nosuid and some sys mounts 11 | filesystems=`mount | egrep -v "nosuid|cgroup|udev|none"| cut -f3 -d" "` 12 | 13 | for fs in $filesystems 14 | do 15 | files=`/usr/bin/find $fs -xdev \( -perm -4000 -o -perm -2000 \) -type f -print 2>/dev/null | /bin/egrep -v "$suid_whitelist"` 16 | if [ -n "$files" ]; then 17 | <% if @dry_run_on_unknown %> 18 | echo "remove from: $files" 19 | <% else %> 20 | chmod ug-s $files 21 | <% end %> 22 | fi 23 | done 24 | -------------------------------------------------------------------------------- /templates/securetty.erb: -------------------------------------------------------------------------------- 1 | # MANAGED BY PUPPET 2 | # A list of TTYs, from which root can log in 3 | # see `man securetty` for reference 4 | <%= @ttys %> 5 | -------------------------------------------------------------------------------- /templates/umask.sh.erb: -------------------------------------------------------------------------------- 1 | # MANAGED BY PUPPET 2 | umask <%= @system_umask %> 3 | -------------------------------------------------------------------------------- /test/fixtures/Puppetfile: -------------------------------------------------------------------------------- 1 | forge "https://forgeapi.puppetlabs.com" 2 | 3 | metadata 4 | 5 | -------------------------------------------------------------------------------- /test/fixtures/manifests.do/site.pp: -------------------------------------------------------------------------------- 1 | # FIX: create module conf dir 2 | 3 | file { '/etc/modprobe.d/': 4 | ensure => directory, 5 | } 6 | 7 | # Apply hardening module 8 | -> class { 'os_hardening': 9 | manage_cron_permissions => true, 10 | } 11 | -------------------------------------------------------------------------------- /test/fixtures/manifests/site.pp: -------------------------------------------------------------------------------- 1 | # FIX: create module conf dir 2 | 3 | file { '/etc/modprobe.d/': 4 | ensure => directory, 5 | } 6 | 7 | # Apply hardening module 8 | -> class { 'os_hardening': 9 | manage_cron_permissions => true, 10 | system_environment => 'docker', 11 | } 12 | -------------------------------------------------------------------------------- /test/fixtures/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardening-os_hardening", 3 | "version": "2.4.0", 4 | "author": "Dominik Richter", 5 | "summary": "Configures the base OS with hardening", 6 | "license": "Apache-2.0", 7 | "source": "https://github.com/dev-sec/puppet-os-hardening.git", 8 | "project_page": "https://github.com/dev-sec/puppet-os-hardening", 9 | "issues_url": "https://github.com/dev-sec/puppet-os-hardening/issues", 10 | "dependencies": [ 11 | { 12 | "name": "puppetlabs/stdlib", 13 | "version_requirement": ">= 4.6.0 < 8.0.0" 14 | }, 15 | { 16 | "name": "herculesteam/augeasproviders_sysctl", 17 | "version_requirement": ">= 2.2.1 < 3.0.0" 18 | } 19 | ], 20 | "operatingsystem_support": [ 21 | { 22 | "operatingsystem": "OracleLinux", 23 | "operatingsystemrelease": [ 24 | "7" 25 | ] 26 | }, 27 | { 28 | "operatingsystem": "CentOS", 29 | "operatingsystemrelease": [ 30 | "7", 31 | "8" 32 | ] 33 | }, 34 | { 35 | "operatingsystem": "OpenSuSE", 36 | "operatingsystemrelease": [ 37 | "15", 38 | "42" 39 | ] 40 | }, 41 | { 42 | "operatingsystem": "RedHat", 43 | "operatingsystemrelease": [ 44 | "7" 45 | ] 46 | }, 47 | { 48 | "operatingsystem": "Debian", 49 | "operatingsystemrelease": [ 50 | "7", 51 | "8", 52 | "9", 53 | "10" 54 | ] 55 | }, 56 | { 57 | "operatingsystem": "SLES", 58 | "operatingsystemrelease": [ 59 | "11", 60 | "12", 61 | "15" 62 | ] 63 | }, 64 | { 65 | "operatingsystem": "Ubuntu", 66 | "operatingsystemrelease": [ 67 | "14", 68 | "16", 69 | "18", 70 | "20" 71 | ] 72 | }, 73 | { 74 | "operatingsystem": "CumulusLinux", 75 | "operatingsystemrelease": [ 76 | "3", 77 | "4" 78 | ] 79 | } 80 | ], 81 | "requirements": [ 82 | { 83 | "name": "puppet", 84 | "version_requirement": ">= 6.0.0 < 9.0.0" 85 | } 86 | ], 87 | "template-url": "https://github.com/dev-sec/puppet-pdk-template#2.3.0", 88 | "pdk-version": "2.3.0", 89 | "template-ref": "tags/2.3.0-0-g8aaceff" 90 | } 91 | -------------------------------------------------------------------------------- /test/integration/digitalocean-linux-baseline/controls/tests.rb: -------------------------------------------------------------------------------- 1 | include_controls 'linux-baseline' do 2 | # /etc/hosts.equiv is not absent everywhere 3 | skip_control 'os-01' 4 | # skip entropy test, as our short living test VMs usually do not have enough 5 | skip_control 'os-08' 6 | # skip filesystem test (vfat enabled for uefi) 7 | skip_control 'os-10' 8 | # No syslog installed in test env 9 | skip_control 'package-07' 10 | # skip auditd tests, we do not have any implementation for audit management yet 11 | skip_control 'package-08' 12 | end 13 | -------------------------------------------------------------------------------- /test/integration/digitalocean-linux-baseline/inspec.yml: -------------------------------------------------------------------------------- 1 | name: integration-tests-digitalocean 2 | version: 1.0.0 3 | depends: 4 | - name: linux-baseline 5 | url: https://github.com/dev-sec/linux-baseline/archive/master.tar.gz 6 | -------------------------------------------------------------------------------- /test/integration/docker-linux-baseline/controls/tests.rb: -------------------------------------------------------------------------------- 1 | include_controls 'linux-baseline' do 2 | # /etc/hosts.equiv is not absent everywhere 3 | skip_control 'os-01' 4 | # skip entropy test, as our short living test VMs usually do not have enough 5 | skip_control 'os-08' 6 | # skip filesystem test (vfat enabled for uefi) 7 | skip_control 'os-10' 8 | # skip mountpoint test 9 | skip_control 'os-14' 10 | # No syslog installed in test env 11 | skip_control 'package-07' 12 | # skip auditd tests, we do not have any implementation for audit management yet 13 | skip_control 'package-08' 14 | 15 | # docker environment - skip all sysctl tests 16 | skip_control 'sysctl-01' 17 | skip_control 'sysctl-02' 18 | skip_control 'sysctl-03' 19 | skip_control 'sysctl-04' 20 | skip_control 'sysctl-05' 21 | skip_control 'sysctl-06' 22 | skip_control 'sysctl-07' 23 | skip_control 'sysctl-08' 24 | skip_control 'sysctl-09' 25 | skip_control 'sysctl-10' 26 | skip_control 'sysctl-11' 27 | skip_control 'sysctl-12' 28 | skip_control 'sysctl-13' 29 | skip_control 'sysctl-14' 30 | skip_control 'sysctl-15' 31 | skip_control 'sysctl-16' 32 | skip_control 'sysctl-17' 33 | skip_control 'sysctl-18' 34 | skip_control 'sysctl-19' 35 | skip_control 'sysctl-20' 36 | skip_control 'sysctl-21' 37 | skip_control 'sysctl-22' 38 | skip_control 'sysctl-23' 39 | skip_control 'sysctl-24' 40 | skip_control 'sysctl-25' 41 | skip_control 'sysctl-26' 42 | skip_control 'sysctl-27' 43 | skip_control 'sysctl-28' 44 | skip_control 'sysctl-29' 45 | skip_control 'sysctl-30' 46 | skip_control 'sysctl-31a' 47 | skip_control 'sysctl-31b' 48 | skip_control 'sysctl-32' 49 | skip_control 'sysctl-33' 50 | end 51 | -------------------------------------------------------------------------------- /test/integration/docker-linux-baseline/inspec.yml: -------------------------------------------------------------------------------- 1 | name: integration-tests-docker 2 | version: 1.0.0 3 | depends: 4 | - name: linux-baseline 5 | url: https://github.com/dev-sec/linux-baseline/archive/master.tar.gz 6 | -------------------------------------------------------------------------------- /tools/fix_permissions: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Fix file + directory permissions for Puppet 3 | 4 | 5 | # module root dir 6 | MODDIR=$(dirname $(readlink -f "$0"))/.. 7 | 8 | # sanity check 9 | if [ ! -r "$MODDIR/metadata.json" ] ; then 10 | echo "Cannot determine module root!" 11 | exit 1 12 | fi 13 | 14 | # fix permissions 15 | find "$MODDIR" -type d -print0 | xargs -0 chmod go+rx 16 | find "$MODDIR" -type f -print0 | xargs -0 chmod go+r 17 | 18 | --------------------------------------------------------------------------------