├── .gitignore ├── .kitchen.yml ├── .rubocop.yml ├── .travis.yml ├── Berksfile ├── CONTRIBUTING.md ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── TESTING.md ├── attributes ├── default.rb └── repo.rb ├── chefignore ├── libraries └── helpers.rb ├── metadata.rb ├── recipes ├── agent_setup.rb ├── debian.rb ├── default.rb └── rhel.rb ├── spec ├── default_spec.rb ├── repo_spec.rb └── spec_helper.rb └── test ├── cookbooks ├── install_old_agent │ ├── attributes │ │ ├── default.rb │ │ └── repo.rb │ ├── metadata.rb │ └── recipes │ │ └── default.rb └── setup │ ├── README.md │ ├── metadata.rb │ └── recipes │ └── default.rb └── integration ├── custom └── serverspec │ └── default_spec.rb ├── data_bags ├── insecure_data_bag_secret └── threatstack │ └── api_keys.json ├── default └── serverspec │ └── default_spec.rb └── upgrades └── serverspec └── default_spec.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *# 3 | .#* 4 | \#*# 5 | .*.sw[a-z] 6 | *.un~ 7 | *.tmp 8 | *.bk 9 | *.bkup 10 | .DS_Store 11 | .kitchen.local.yml 12 | .rspec 13 | .yardopts 14 | Gemfile.lock 15 | Berksfile.lock 16 | .bundle/ 17 | .cache/ 18 | .kitchen/ 19 | .vagrant/ 20 | .vagrant.d/ 21 | .yardoc/ 22 | bin/ 23 | doc/ 24 | tmp/ 25 | vendor/ 26 | VERSION 27 | #rbenv for local development 28 | .ruby-version 29 | -------------------------------------------------------------------------------- /.kitchen.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: docker 4 | 5 | provisioner: 6 | product_name: chef 7 | product_version: 15 8 | 9 | platforms: 10 | - name: amazonlinux-1 11 | attributes: 12 | threatstack: 13 | repo: 14 | url: <%= ENV['TS_RPM_REPO_URL'] != nil ? ENV['TS_RPM_REPO_URL'] + '/Amazon/1' : nil %> 15 | key_file_uri: <%= ENV['TS_RPM_REPO_URL'] != nil ? ENV['TS_RPM_REPO_URL'] + '/Amazon/1/repomd.xml.key' : nil %> 16 | validate_gpg_key: false # This is ONLY for test purposes! Don't do this in your actual roles/recipes 17 | driver_config: 18 | image: amazonlinux:1 19 | run_command: /sbin/init 20 | privileged: true 21 | run_options: 22 | env: container=docker 23 | volume: 24 | - /sys/fs/cgroup:/sys/fs/cgroup 25 | provision_command: 26 | - yum install -y audit initscripts 27 | - sed -i 's/local_events = yes/local_events = no/g' /etc/audit/auditd.conf 28 | - chkconfig auditd on 29 | - name: amazonlinux-2 30 | attributes: 31 | threatstack: 32 | repo: 33 | url: <%= ENV['TS_RPM_REPO_URL'] != nil ? ENV['TS_RPM_REPO_URL'] + '/Amazon/2' : nil %> 34 | key_file_uri: <%= ENV['TS_RPM_REPO_URL'] != nil ? ENV['TS_RPM_REPO_URL'] + '/Amazon/2/repomd.xml.key' : nil %> 35 | validate_gpg_key: false # This is ONLY for test purposes! Don't do this in your actual roles/recipes 36 | driver_config: 37 | image: amazonlinux:2 38 | run_command: /sbin/init 39 | privileged: true 40 | run_options: 41 | env: container=docker 42 | volume: 43 | - /sys/fs/cgroup:/sys/fs/cgroup 44 | provision_command: 45 | - yum install -y audit initscripts 46 | - sed -i 's/local_events = yes/local_events = no/g' /etc/audit/auditd.conf 47 | - systemctl enable auditd.service 48 | - name: amazonlinux-2-arm 49 | attributes: 50 | threatstack: 51 | repo: 52 | url: <%= ENV['TS_RPM_REPO_URL'] != nil ? ENV['TS_RPM_REPO_URL'] + '/Amazon/2' : nil %> 53 | key_file_uri: <%= ENV['TS_RPM_REPO_URL'] != nil ? ENV['TS_RPM_REPO_URL'] + '/Amazon/2/repomd.xml.key' : nil %> 54 | validate_gpg_key: false # This is ONLY for test purposes! Don't do this in your actual roles/recipes 55 | driver_config: 56 | image: arm64v8/amazonlinux:2 57 | run_command: /sbin/init 58 | privileged: true 59 | run_options: 60 | env: container=docker 61 | volume: 62 | - /sys/fs/cgroup:/sys/fs/cgroup 63 | provision_command: 64 | - yum install -y audit initscripts 65 | - sed -i 's/local_events = yes/local_events = no/g' /etc/audit/auditd.conf 66 | - systemctl enable auditd.service 67 | - name: centos-7 68 | attributes: 69 | threatstack: 70 | repo: 71 | url: <%= ENV['TS_RPM_REPO_URL'] != nil ? ENV['TS_RPM_REPO_URL'] + '/EL/7' : nil %> 72 | key_file_uri: <%= ENV['TS_RPM_REPO_URL'] != nil ? ENV['TS_RPM_REPO_URL'] + '/EL/7/repomd.xml.key' : nil %> 73 | validate_gpg_key: false # This is ONLY for test purposes! Don't do this in your actual roles/recipes 74 | driver_config: 75 | image: centos:7 76 | run_command: /sbin/init 77 | privileged: true 78 | run_options: 79 | env: container=docker 80 | volume: 81 | - /sys/fs/cgroup:/sys/fs/cgroup 82 | provision_command: 83 | - yum install -y audit initscripts 84 | - sed -i 's/local_events = yes/local_events = no/g' /etc/audit/auditd.conf 85 | - systemctl enable auditd.service 86 | - name: centos-8 87 | attributes: 88 | threatstack: 89 | repo: 90 | url: <%= ENV['TS_RPM_REPO_URL'] != nil ? ENV['TS_RPM_REPO_URL'] + '/EL/8' : nil %> 91 | key_file_uri: <%= ENV['TS_RPM_REPO_URL'] != nil ? ENV['TS_RPM_REPO_URL'] + '/EL/8/repomd.xml.key' : nil %> 92 | validate_gpg_key: false # This is ONLY for test purposes! Don't do this in your actual roles/recipes 93 | driver_config: 94 | image: centos:8 95 | run_command: /sbin/init 96 | privileged: true 97 | run_options: 98 | env: container=docker 99 | volume: 100 | - /sys/fs/cgroup:/sys/fs/cgroup 101 | provision_command: 102 | - yum install -y audit initscripts 103 | - sed -i 's/local_events = yes/local_events = no/g' /etc/audit/auditd.conf 104 | - systemctl enable auditd.service 105 | - name: centos-8-arm 106 | attributes: 107 | threatstack: 108 | repo: 109 | url: <%= ENV['TS_RPM_REPO_URL'] != nil ? ENV['TS_RPM_REPO_URL'] + '/EL/8' : nil %> 110 | key_file_uri: <%= ENV['TS_RPM_REPO_URL'] != nil ? ENV['TS_RPM_REPO_URL'] + '/EL/8/repomd.xml.key' : nil %> 111 | validate_gpg_key: false # This is ONLY for test purposes! Don't do this in your actual roles/recipes 112 | driver_config: 113 | image: arm64v8/centos:8 114 | run_command: /sbin/init 115 | privileged: true 116 | run_options: 117 | env: container=docker 118 | volume: 119 | - /sys/fs/cgroup:/sys/fs/cgroup 120 | provision_command: 121 | - yum install -y audit initscripts 122 | - sed -i 's/local_events = yes/local_events = no/g' /etc/audit/auditd.conf 123 | - systemctl enable auditd.service 124 | - name: debian-8 125 | attributes: 126 | threatstack: 127 | repo: 128 | url: <%= ENV['TS_DEB_REPO_URL'] != nil ? ENV['TS_DEB_REPO_URL']: nil %> 129 | key: <%= ENV['TS_DEB_REPO_KEY'] != nil ? ENV['TS_DEB_REPO_KEY'] : nil %> 130 | components: <%= ENV['TS_REPO_COMPONENTS'] != nil ? ENV['TS_REPO_COMPONENTS'] : nil %> 131 | driver_config: 132 | image: debian:8 133 | run_command: /sbin/init 134 | cap_add: 135 | - SYS_ADMIN 136 | run_options: 137 | env: container=docker 138 | volume: 139 | - /sys/fs/cgroup:/sys/fs/cgroup 140 | provision_command: 141 | - sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config 142 | - systemctl enable ssh.service 143 | - name: debian-9 144 | attributes: 145 | threatstack: 146 | repo: 147 | url: <%= ENV['TS_DEB_REPO_URL'] != nil ? ENV['TS_DEB_REPO_URL']: nil %> 148 | key: <%= ENV['TS_DEB_REPO_KEY'] != nil ? ENV['TS_DEB_REPO_KEY'] : nil %> 149 | components: <%= ENV['TS_REPO_COMPONENTS'] != nil ? ENV['TS_REPO_COMPONENTS'] : nil %> 150 | driver_config: 151 | image: debian:9 152 | run_command: /bin/systemd 153 | cap_add: 154 | - SYS_ADMIN 155 | run_options: 156 | env: container=docker 157 | volume: 158 | - /sys/fs/cgroup:/sys/fs/cgroup 159 | provision_command: 160 | - sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config 161 | - systemctl enable ssh.service 162 | - apt install -y gnupg 163 | - name: debian-10 164 | attributes: 165 | threatstack: 166 | repo: 167 | url: <%= ENV['TS_DEB_REPO_URL'] != nil ? ENV['TS_DEB_REPO_URL']: nil %> 168 | key: <%= ENV['TS_DEB_REPO_KEY'] != nil ? ENV['TS_DEB_REPO_KEY'] : nil %> 169 | components: <%= ENV['TS_REPO_COMPONENTS'] != nil ? ENV['TS_REPO_COMPONENTS'] : nil %> 170 | driver_config: 171 | image: debian:10 172 | run_command: /sbin/init 173 | cap_add: 174 | - SYS_ADMIN 175 | run_options: 176 | env: container=docker 177 | volume: 178 | - /sys/fs/cgroup:/sys/fs/cgroup 179 | provision_command: 180 | - sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config 181 | - systemctl enable ssh.service 182 | - apt install -y gnupg 183 | - name: debian-10-arm 184 | attributes: 185 | threatstack: 186 | repo: 187 | url: <%= ENV['TS_DEB_REPO_URL'] != nil ? ENV['TS_DEB_REPO_URL']: nil %> 188 | key: <%= ENV['TS_DEB_REPO_KEY'] != nil ? ENV['TS_DEB_REPO_KEY'] : nil %> 189 | components: <%= ENV['TS_REPO_COMPONENTS'] != nil ? ENV['TS_REPO_COMPONENTS'] : nil %> 190 | driver_config: 191 | image: arm64v8/debian:10 192 | run_command: /sbin/init 193 | cap_add: 194 | - SYS_ADMIN 195 | run_options: 196 | env: container=docker 197 | volume: 198 | - /sys/fs/cgroup:/sys/fs/cgroup 199 | provision_command: 200 | - sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config 201 | - systemctl enable ssh.service 202 | - apt install -y gnupg 203 | - name: ubuntu-16.04 204 | attributes: 205 | threatstack: 206 | repo: 207 | url: <%= ENV['TS_DEB_REPO_URL'] != nil ? ENV['TS_DEB_REPO_URL']: nil %> 208 | key: <%= ENV['TS_DEB_REPO_KEY'] != nil ? ENV['TS_DEB_REPO_KEY'] : nil %> 209 | components: <%= ENV['TS_REPO_COMPONENTS'] != nil ? ENV['TS_REPO_COMPONENTS'] : nil %> 210 | driver_config: 211 | image: ubuntu:16.04 212 | run_command: /sbin/init 213 | cap_add: 214 | - SYS_ADMIN 215 | run_options: 216 | env: container=docker 217 | volume: 218 | - /sys/fs/cgroup:/sys/fs/cgroup 219 | provision_command: 220 | - sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config 221 | - systemctl enable ssh.service 222 | - apt install -y gnupg 223 | - name: ubuntu-18.04 224 | attributes: 225 | threatstack: 226 | repo: 227 | url: <%= ENV['TS_DEB_REPO_URL'] != nil ? ENV['TS_DEB_REPO_URL']: nil %> 228 | key: <%= ENV['TS_DEB_REPO_KEY'] != nil ? ENV['TS_DEB_REPO_KEY'] : nil %> 229 | components: <%= ENV['TS_REPO_COMPONENTS'] != nil ? ENV['TS_REPO_COMPONENTS'] : nil %> 230 | driver_config: 231 | image: ubuntu:18.04 232 | run_command: /sbin/init 233 | cap_add: 234 | - SYS_ADMIN 235 | run_options: 236 | env: container=docker 237 | volume: 238 | - /sys/fs/cgroup:/sys/fs/cgroup 239 | provision_command: 240 | - sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config 241 | - systemctl enable ssh.service 242 | - apt install -y gnupg 243 | - name: ubuntu-18.04-arm 244 | attributes: 245 | threatstack: 246 | repo: 247 | url: <%= ENV['TS_DEB_REPO_URL'] != nil ? ENV['TS_DEB_REPO_URL']: nil %> 248 | key: <%= ENV['TS_DEB_REPO_KEY'] != nil ? ENV['TS_DEB_REPO_KEY'] : nil %> 249 | components: <%= ENV['TS_REPO_COMPONENTS'] != nil ? ENV['TS_REPO_COMPONENTS'] : nil %> 250 | driver_config: 251 | image: arm64v8/ubuntu:18.04 252 | run_command: /sbin/init 253 | cap_add: 254 | - SYS_ADMIN 255 | run_options: 256 | env: container=docker 257 | volume: 258 | - /sys/fs/cgroup:/sys/fs/cgroup 259 | provision_command: 260 | - sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config 261 | - systemctl enable ssh.service 262 | - apt install -y gnupg 263 | - name: ubuntu-20.04 264 | attributes: 265 | threatstack: 266 | repo: 267 | url: <%= ENV['TS_DEB_REPO_URL'] != nil ? ENV['TS_DEB_REPO_URL']: nil %> 268 | key: <%= ENV['TS_DEB_REPO_KEY'] != nil ? ENV['TS_DEB_REPO_KEY'] : nil %> 269 | components: <%= ENV['TS_REPO_COMPONENTS'] != nil ? ENV['TS_REPO_COMPONENTS'] : nil %> 270 | driver_config: 271 | image: ubuntu:20.04 272 | run_command: /sbin/init 273 | cap_add: 274 | - SYS_ADMIN 275 | run_options: 276 | env: container=docker 277 | volume: 278 | - /sys/fs/cgroup:/sys/fs/cgroup 279 | provision_command: 280 | - sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config 281 | - systemctl enable ssh.service 282 | - apt install -y gnupg 283 | - name: ubuntu-20.04-arm 284 | attributes: 285 | threatstack: 286 | repo: 287 | url: <%= ENV['TS_DEB_REPO_URL'] != nil ? ENV['TS_DEB_REPO_URL']: nil %> 288 | key: <%= ENV['TS_DEB_REPO_KEY'] != nil ? ENV['TS_DEB_REPO_KEY'] : nil %> 289 | components: <%= ENV['TS_REPO_COMPONENTS'] != nil ? ENV['TS_REPO_COMPONENTS'] : nil %> 290 | driver_config: 291 | image: arm64v8/ubuntu:20.04 292 | run_command: /sbin/init 293 | cap_add: 294 | - SYS_ADMIN 295 | run_options: 296 | env: container=docker 297 | volume: 298 | - /sys/fs/cgroup:/sys/fs/cgroup 299 | provision_command: 300 | - sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config 301 | - systemctl enable ssh.service 302 | - apt install -y gnupg 303 | 304 | suites: 305 | - name: default 306 | run_list: 307 | - recipe[setup] 308 | - recipe[threatstack] 309 | provisioner: 310 | encrypted_data_bag_secret_key_path: test/integration/data_bags/insecure_data_bag_secret 311 | attributes: 312 | apt: 313 | compile_time_update: true 314 | threatstack: 315 | deploy_key: <%= ENV['TS_DEPLOY_KEY'] != nil ? ENV['TS_DEPLOY_KEY'] : nil %> 316 | url: <%= ENV['TS_URL'] != nil ? ENV['TS_URL'] : nil %> 317 | version: <%= ENV['TS_PACKAGE_VERSION'] != nil ? ENV['TS_PACKAGE_VERSION'] : nil %> 318 | configure_agent: <%= ENV['TS_CONFIG_AGENT'] == '0' ? false : true %> 319 | - name: upgrades 320 | run_list: 321 | - recipe[setup] 322 | - recipe[install_old_agent] 323 | - recipe[threatstack] 324 | provisioner: 325 | encrypted_data_bag_secret_key_path: test/integration/data_bags/insecure_data_bag_secret 326 | excludes: 327 | - debian-10 328 | - ubuntu-20.04 329 | - centos-8 330 | attributes: 331 | apt: 332 | compile_time_update: true 333 | threatstack: 334 | deploy_key: <%= ENV['TS_DEPLOY_KEY'] != nil ? ENV['TS_DEPLOY_KEY'] : nil %> 335 | url: <%= ENV['TS_URL'] != nil ? ENV['TS_URL'] : nil %> 336 | version: <%= ENV['TS_PACKAGE_VERSION'] != nil ? ENV['TS_PACKAGE_VERSION'] : nil %> 337 | configure_agent: <%= ENV['TS_CONFIG_AGENT'] == '0' ? false : true %> 338 | agent_config_args: <%= ENV['TS_CONFIG_ARGS'] != nil ? ENV['TS_CONFIG_ARGS'] : "['log.maxSize 22']" %> 339 | - name: custom 340 | run_list: 341 | - recipe[setup] 342 | - recipe[threatstack] 343 | provisioner: 344 | encrypted_data_bag_secret_key_path: test/integration/data_bags/insecure_data_bag_secret 345 | attributes: 346 | apt: 347 | compile_time_update: true 348 | threatstack: 349 | deploy_key: <%= ENV['TS_DEPLOY_KEY'] != nil ? ENV['TS_DEPLOY_KEY'] : nil %> 350 | url: <%= ENV['TS_URL'] != nil ? ENV['TS_URL'] : nil %> 351 | version: <%= ENV['TS_PACKAGE_VERSION'] != nil ? ENV['TS_PACKAGE_VERSION'] : nil %> 352 | agent_config_args: <%= ENV['TS_CONFIG_ARGS'] != nil ? ENV['TS_CONFIG_ARGS'] : ['log.maxSize 22'] %> 353 | configure_agent: <%= ENV['TS_CONFIG_AGENT'] == '0' ? false : true %> 354 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | Exclude: 3 | - metadata.rb 4 | - Rakefile 5 | - vendor/**/* 6 | - spec/**/* 7 | - Gemfile 8 | 9 | Style/ConditionalAssignment: 10 | Enabled: false 11 | Style/FrozenStringLiteralComment: 12 | Enabled: false 13 | Layout/LineLength: 14 | Enabled: false 15 | Metrics/BlockNesting: 16 | Enabled: false 17 | Style/IfUnlessModifier: 18 | Enabled: false 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | bundler_args: "--without system_tests" 3 | script: 4 | - bundle exec rake 5 | cache: bundler 6 | sudo: required 7 | rvm: 8 | - 2.4 9 | - 2.5 10 | - 2.6 11 | before_install: 12 | - gem update --system 3.0.2 13 | env: 14 | - CHEF_VERSION="= 12.21.14" 15 | - CHEF_VERSION=">= 0.0.0" # installs latest 16 | 17 | matrix: 18 | exclude: 19 | - rvm: 2.4 20 | env: CHEF_VERSION="= 12.21.14" 21 | 22 | notifications: 23 | slack: 24 | secure: Kqp/g7ta+JzAklXhTIl+ZU+FqrdXJe7DNWuqDZXec4YLLB9pFR1MpUyW1kx+WBcb7Fc//w4Q+1NLn02Slg9ay1xkRkNVi1UInUk89ocqwPbsmESA/690fnRba+C7mW/6D3Z+C7AMPQeZszhcRVzX1xrH3b3xlvLMvyFk/UnQOMU= 25 | -------------------------------------------------------------------------------- /Berksfile: -------------------------------------------------------------------------------- 1 | source 'https://supermarket.chef.io' 2 | 3 | metadata 4 | 5 | cookbook 'setup', path: './test/cookbooks/setup', group: :integration 6 | cookbook 'install_old_agent', path: './test/cookbooks/install_old_agent', group: :integration 7 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing to Threat Stack Agent Chef Recipe 2 | ============================= 3 | 4 | We encourage anyone to provide enchancements/fixes to this repository. Simply fork, commit, and then open a PR back to the parent repository. 5 | 6 | 7 | ### What makes a good PR? 8 | 9 | * Make sure you update the README.md with any new/removed/changed values parameters. 10 | * Write tests that cover your proposed changes. (See the [TESTING](TESTING.md) documentation) 11 | * Make sure the tests documented in the [README](README.md) run as expected on all platforms. 12 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source ENV['GEM_SOURCE'] || 'https://rubygems.org' 2 | 3 | group :development, :unit_tests , :test do 4 | gem 'rake', "13.0.3", :require => false 5 | gem 'chefspec', '= 7.3.4', :require => false 6 | gem 'berkshelf', '= 6.3.4' 7 | gem 'cookstyle', '= 6.16.10' 8 | end 9 | 10 | group :system_tests do 11 | gem 'serverspec', :require => false 12 | gem 'test-kitchen', :require => false 13 | gem 'kitchen-docker', :require => false 14 | gem 'kitchen-ec2', :require => false 15 | end 16 | 17 | if chefversion = ENV['CHEF_VERSION'] 18 | gem 'chef', chefversion 19 | else 20 | gem 'chef' 21 | end 22 | -------------------------------------------------------------------------------- /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 2015 Threat Stack 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 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Threat Stack Cookbook 2 | ================ 3 | 4 | [![Build Status](https://travis-ci.org/threatstack/threatstack-chef.svg?branch=master)][travis] 5 | [![Cookbook Version](http://img.shields.io/cookbook/v/threatstack.svg)][cookbook] 6 | 7 | [travis]: https://travis-ci.org/threatstack/threatstack-chef 8 | [cookbook]: https://supermarket.chef.io/cookbooks/threatstack 9 | 10 | **NOTE**: As of 3.x of this cookbook we only explicitly support version 2.x of the threatstack agent and greater. 11 | 12 | Chef recipes to deploy the Threat Stack server agent 13 | 14 | Requirements 15 | ============ 16 | - chef > 12.15 17 | 18 | Platforms 19 | --------- 20 | 21 | * Amazon Linux 22 | * CentOS 23 | * RedHat 24 | * Ubuntu 25 | * Debian 26 | 27 | Cookbooks 28 | --------- 29 | 30 | The following Opscode cookbooks are dependencies: 31 | 32 | * `apt` 33 | * `yum` 34 | 35 | Recipes 36 | ======= 37 | 38 | default 39 | ------- 40 | Installs the Threat Stack agent package and register the agent with the service 41 | 42 | repo 43 | -------- 44 | Sets up the Apt or Yum repo for installing the Threat Stack agent package 45 | 46 | Usage 47 | ===== 48 | 49 | 1. Add this cookbook to your Chef Server or add to your Berksfile 50 | ``` 51 | cookbook 'threatstack', '~> 3.0.0' 52 | ``` 53 | 54 | 2. Add your deploy api key. The recommended way is to use an encrypted databag 55 | with name and item specified by the corresponding attributes. The cookbook will 56 | use the `'deploy_key'` value from the databag by default. 57 | You can also set the key directly or using a wrapper cookbook in the `node['threatstack']['deploy_key']` attribute. 58 | Setting the key will disable the encrypted data bag lookup. 59 | 60 | Additionally you we can read the deploy key from the `node.run_state['threatstack']['deploy_key']` location 61 | Simply set the value of the deploy key in the run state at that location. 62 | 63 | 3. Set the `node['threatstack']['rulesets']` appropriately for your node(s). This attribute is an array. 64 | 65 | 4. Add this recipe to your runlist or include in another recipe 66 | 67 | Attributes 68 | ========== 69 | 70 | `node['threatstack']['version']` - Set to pin to a specific Threat Stack agent release version. 71 | 72 | `node['threatstack']['rulesets']` - (Required) Set this with an array of ruleset(s) to apply to the node 73 | 74 | `node['threatstack']['hostname']` - register the agent in the UI by a specific name (defaults to hostname). 75 | 76 | `node['threatstack']['ignore_failure']` - Set to true if you want the install to silently fail. 77 | 78 | `node['threatstack']['deploy_key']` - (Required) Override this with your deploy key for agent registration 79 | 80 | `node['threatstack']['data_bag_name']` - Name of the encrypted databag containing Threat Stack secrets 81 | 82 | `node['threatstack']['data_bag_item']` - Name of the encrypted databag item containing Threat Stack secrets 83 | 84 | `node['threatstack']['agent_config_args']` - Additional configuration settings for setting up agent 85 | 86 | `node['threatstack']['enable_containers']` - Set this to true in order to enable container observation. Note: container capability must already be installed and running. 87 | 88 | 89 | Encrypted Data Bag Contents 90 | =========================== 91 | `deploy_key` - the deploy key for agent registration. 92 | 93 | Contributing enhancements/fixes 94 | =============================== 95 | See the [CONTRIBUTING document](CONTRIBUTING.md) for details. 96 | 97 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rspec/core/rake_task' 2 | require 'rubocop/rake_task' 3 | require 'cookstyle' 4 | 5 | # Style tests. Cookstyle combines foodcritic and rubocop. 6 | namespace :style do 7 | RuboCop::RakeTask.new(:cookstyle) do |task| 8 | task.options << '--display-cop-names' 9 | end 10 | end 11 | 12 | desc 'Run all style checks' 13 | task style: ['style:cookstyle'] 14 | 15 | # Rspec and ChefSpec 16 | desc "Run ChefSpec examples" 17 | RSpec::Core::RakeTask.new(:spec) do |t| 18 | t.rspec_opts = '--format documentation' 19 | end 20 | 21 | # Default 22 | task default: ['style', 'spec'] 23 | -------------------------------------------------------------------------------- /TESTING.md: -------------------------------------------------------------------------------- 1 | ## Testing the cookbook 2 | 3 | This cookbook has tests in the source repository. To run the tests: 4 | 5 | ``` 6 | git clone git://github.com/threatstack/threatstack-chef.git 7 | cd threatstack-chef 8 | bundle install 9 | ``` 10 | 11 | There are two kinds of tests in use: unit and integration tests. 12 | 13 | ### Unit Tests 14 | 15 | The chef recipe is unit tested with chefspec, with additional linting with Foodcritic and Rubocop 16 | To run spec tests only: 17 | 18 | ``` 19 | bundle exec rake spec 20 | ``` 21 | 22 | To run linting only: 23 | ``` 24 | bundle exec rake style 25 | ``` 26 | To run all unit and linting tests: 27 | ``` 28 | bundle exec rake 29 | ``` 30 | 31 | ### Integration Tests 32 | 33 | This tests a number of different integration test suites using docker containers. They are 34 | setup to run under test-kitchen: 35 | 36 | Requirements: 37 | To run integration testing you need a valid threatstack agent deployment key 38 | Get your deployment key from the Threat Stack application under "Settings" -> "Applications Keys" 39 | 40 | **Example:** 41 | ``` 42 | export TS_DEPLOY_KEY= 43 | export TS_CONFIG_ARGS=['fim.log yes'] 44 | ``` 45 | 46 | Local container integration testing 47 | --------------- 48 | Container (with docker) testing through the Kitchen-CI toolset can be done locally. You must have 49 | docker installed. The `.kitchen.yml` file drives the configuration and execution of the tests. 50 | 51 | To run tests, use the kitchen framework. The following will run all tests: 52 | ``` 53 | bundle exec kitchen test 54 | ``` 55 | -------------------------------------------------------------------------------- /attributes/default.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Cookbook:: threatstack 3 | # Attributes:: default 4 | # 5 | # Copyright:: 2014-2020, Threat Stack 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | default['threatstack']['version'] = nil 21 | # If no rulesets are specified the agent will register to the default 22 | # rule set, according to a comment in recipes/default.rb 23 | default['threatstack']['rulesets'] = [] 24 | default['threatstack']['hostname'] = nil 25 | default['threatstack']['ignore_failure'] = false 26 | 27 | # You can set the deploy key directly, or use the encrypted databag 28 | # parameters below. The value searched for will be 'deploy_key' 29 | default['threatstack']['deploy_key'] = nil 30 | default['threatstack']['data_bag_name'] = 'threatstack' 31 | default['threatstack']['data_bag_item'] = 'api_keys' 32 | 33 | # Control the configuration of the Threat Stack agent. Useful when installing 34 | # agent into images. 35 | default['threatstack']['agent_config_args'] = [] 36 | 37 | # To enable host-based containers observation 38 | default['threatstack']['enable_containers'] = nil 39 | 40 | # To install the agent, but skip configuration for later, set this flag to true 41 | # This can be useful in the case of baking an AMI for deployment later 42 | default['threatstack']['install_only'] = false 43 | -------------------------------------------------------------------------------- /attributes/repo.rb: -------------------------------------------------------------------------------- 1 | default['threatstack']['repo_enable'] = true 2 | default['threatstack']['validate_gpg_key'] = true 3 | default['threatstack']['repo']['components'] = ['main'] 4 | 5 | case node['platform_family'] 6 | when 'debian' 7 | default['threatstack']['repo']['dist'] = node['lsb']['codename'] 8 | default['threatstack']['repo']['url'] = 'https://pkg.threatstack.com/v2/Ubuntu' 9 | default['threatstack']['repo']['key'] = 'https://app.threatstack.com/APT-GPG-KEY-THREATSTACK' 10 | when 'rhel', 'fedora', 'amazon' 11 | case node['platform'] 12 | when 'amazon' 13 | if node['platform_version'] == '2' 14 | default['threatstack']['repo']['url'] = 'https://pkg.threatstack.com/v2/Amazon/2' 15 | else 16 | default['threatstack']['repo']['url'] = 'https://pkg.threatstack.com/v2/Amazon/1' 17 | end 18 | when 'centos', 'redhat' 19 | default['threatstack']['repo']['url'] = "https://pkg.threatstack.com/v2/EL/#{node['platform_version'].to_i}" 20 | else 21 | default['threatstack']['repo']['url'] = 'https://pkg.threatstack.com/v2/EL/7' 22 | end 23 | default['threatstack']['repo']['key'] = 'https://app.threatstack.com/RPM-GPG-KEY-THREATSTACK' 24 | default['threatstack']['repo']['key_file'] = '/etc/pki/rpm-gpg/RPM-GPG-KEY-THREATSTACK' 25 | default['threatstack']['repo']['key_file_uri'] = 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-THREATSTACK' 26 | end 27 | -------------------------------------------------------------------------------- /chefignore: -------------------------------------------------------------------------------- 1 | # Put files/directories that should be ignored in this file when uploading 2 | # or sharing to the community site. 3 | # Lines that start with '# ' are comments. 4 | 5 | # OS generated files # 6 | ###################### 7 | .DS_Store 8 | Icon? 9 | nohup.out 10 | ehthumbs.db 11 | Thumbs.db 12 | 13 | # SASS # 14 | ######## 15 | .sass-cache 16 | 17 | # EDITORS # 18 | ########### 19 | \#* 20 | .#* 21 | *~ 22 | *.sw[a-z] 23 | *.bak 24 | REVISION 25 | TAGS* 26 | tmtags 27 | *_flymake.* 28 | *_flymake 29 | *.tmproj 30 | .project 31 | .settings 32 | mkmf.log 33 | 34 | ## COMPILED ## 35 | ############## 36 | a.out 37 | *.o 38 | *.pyc 39 | *.so 40 | *.com 41 | *.class 42 | *.dll 43 | *.exe 44 | */rdoc/ 45 | 46 | # Testing # 47 | ########### 48 | .watchr 49 | .rspec 50 | spec/* 51 | spec/fixtures/* 52 | test/* 53 | features/* 54 | Guardfile 55 | Procfile 56 | 57 | # SCM # 58 | ####### 59 | .git 60 | */.git 61 | .gitignore 62 | .gitmodules 63 | .gitconfig 64 | .gitattributes 65 | .svn 66 | */.bzr/* 67 | */.hg/* 68 | */.svn/* 69 | 70 | # Berkshelf # 71 | ############# 72 | Berksfile 73 | Berksfile.lock 74 | cookbooks/* 75 | tmp 76 | 77 | # Cookbooks # 78 | ############# 79 | CONTRIBUTING 80 | 81 | # Strainer # 82 | ############ 83 | Colanderfile 84 | Strainerfile 85 | .colander 86 | .strainer 87 | 88 | # Vagrant # 89 | ########### 90 | .vagrant 91 | Vagrantfile 92 | 93 | # Travis # 94 | ########## 95 | .travis.yml 96 | -------------------------------------------------------------------------------- /libraries/helpers.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Cookbook:: threatstack 3 | # Library:: helper 4 | # 5 | # Copyright:: 2014-2021, Threat Stack 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | def tsagent_info?(maj, min, patch) 20 | return true if (maj >= 2 && min >= 2) || (maj >= 2 && min >= 1 && patch >= 3) 21 | 22 | false 23 | end 24 | 25 | def unregistered_agent? 26 | require 'open3' 27 | require 'yaml' 28 | require 'date' 29 | 30 | # By the time this helper is hit, tsagent should exist - but, for tests it does not. 31 | # Fair to say that the agent is *definitely* unregistered if tsagent isnt installed :) 32 | return true unless ::File.exist?('/usr/bin/tsagent') 33 | 34 | stdout, = Open3.capture3('/usr/bin/tsagent info') 35 | stdout.gsub!("\t", ' ') 36 | tsagent_info = YAML.safe_load(stdout) 37 | 38 | return true if tsagent_info['LastBackendConnection'] == 'N/A' 39 | 40 | # It could be stale if it last connected >24h ago. Would need to exec tsagent status and search 41 | # for "UP Threat Stack Backend Connection" along with this to know for sure. 42 | # return true if (DateTime.now.to_time - tsagent_info['LastBackendConnection']) / 3600 > 24.0 43 | 44 | # otherwise, probably fresh. 45 | false 46 | end 47 | -------------------------------------------------------------------------------- /metadata.rb: -------------------------------------------------------------------------------- 1 | name 'threatstack' 2 | maintainer 'Threat Stack' 3 | maintainer_email 'support@threatstack.com' 4 | license 'Apache-2.0' 5 | description 'Installs/Configures Threat Stack agent components' 6 | long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) 7 | version '3.0.6' 8 | issues_url 'https://github.com/threatstack/threatstack-chef/issues' if respond_to?(:issues_url) 9 | source_url 'https://github.com/threatstack/threatstack-chef' if respond_to?(:source_url) 10 | 11 | supports 'amazon' 12 | supports 'centos' 13 | supports 'redhat' 14 | supports 'ubuntu' 15 | 16 | chef_version '>= 12.15' if respond_to?(:chef_version) 17 | -------------------------------------------------------------------------------- /recipes/agent_setup.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Cookbook:: threatstack 3 | # Recipe:: default 4 | # 5 | # Copyright:: 2014-2020, Threat Stack 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | service 'threatstack' do 20 | supports status: true, restart: true, start: true, stop: true 21 | if platform?('amazon') && node['platform_version'] != '2' 22 | provider Chef::Provider::Service::Upstart 23 | end 24 | end 25 | 26 | if node.run_state.key?('threatstack') 27 | if node.run_state['threatstack'].key?('deploy_key') 28 | deploy_key = node.run_state['threatstack']['deploy_key'] 29 | end 30 | elsif node['threatstack']['deploy_key'] 31 | deploy_key = node['threatstack']['deploy_key'] 32 | else 33 | deploy_key = data_bag_item( 34 | node['threatstack']['data_bag_name'], 35 | node['threatstack']['data_bag_item'] 36 | )['deploy_key'] 37 | end 38 | 39 | if deploy_key.nil? || deploy_key.empty? 40 | raise 'No Threat Stack deploy key found in run state, attributes, or data bag. Cannot continue.' 41 | end 42 | 43 | # Register the Threat Stack agent - Rulesets are not required 44 | # and if it's omitted then the agent will be placed into a 45 | # default rule set (most likely 'Base Rule Set') 46 | cmd = '' 47 | cmd += "tsagent setup --deploy-key=#{deploy_key}" 48 | cmd += " --hostname='#{node['threatstack']['hostname']}'" if node['threatstack']['hostname'] 49 | cmd += " --url='#{node['threatstack']['url']}'" if node['threatstack']['url'] 50 | 51 | # Handle rulesets here, multiple rulesets are supported. 52 | unless node['threatstack']['rulesets'].empty? 53 | rulesets_string = node['threatstack']['rulesets'].join(',') 54 | cmd += " --ruleset='#{rulesets_string}'" 55 | end 56 | 57 | #### Setup happens here #### 58 | execute 'tsagent setup' do 59 | command cmd 60 | action :run 61 | retries 3 62 | timeout 60 63 | ignore_failure node['threatstack']['ignore_failure'] 64 | sensitive true 65 | not_if { ::File.exist?('/opt/threatstack/etc/agent.db') } 66 | # default to delayed start in case config is needed. 67 | notifies :start, 'service[threatstack]' 68 | end 69 | 70 | #### Config-specific work below #### 71 | # tsagent configuration settings/flags 72 | # We need to create a duplicate of the node attribute 73 | # since we may change the variable's value later. 74 | agent_config_args = node['threatstack']['agent_config_args'].dup 75 | 76 | # By default, container observation is off; this setting will 77 | # turn it on. 78 | if node['threatstack']['enable_containers'] == true 79 | agent_config_args.push('enable_containers 1') 80 | end 81 | 82 | # Additional configuration options are set here. 83 | config_command = '' 84 | unless agent_config_args.empty? 85 | agent_config_args.each do |arg| 86 | config_command += "tsagent config --set #{arg}; " 87 | end 88 | end 89 | 90 | # Store config statements in a file, which will help us understand 91 | # if they have changed since previous chef runs, and determine if we should 92 | # restart the agent so new config goes into effect. 93 | file '/opt/threatstack/etc/chef_args_cache.txt' do 94 | content config_command 95 | owner 'root' 96 | group 'root' 97 | mode '0644' 98 | action :create 99 | not_if { config_command == '' } 100 | notifies :run, 'execute[tsagent config]', :immediately 101 | end 102 | 103 | # Config must be run prior to starting the agent. If config is run after the agent is 104 | # started, then the agent must be restarted. 105 | execute 'tsagent config' do 106 | command config_command 107 | retries 3 108 | timeout 10 109 | action :nothing 110 | notifies :restart, 'service[threatstack]' 111 | end 112 | -------------------------------------------------------------------------------- /recipes/debian.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Cookbook:: threatstack 3 | # Recipe:: debian 4 | # 5 | # Copyright:: 2014-2020, Threat Stack 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | package 'apt-transport-https' 21 | 22 | apt_repository 'threatstack' do 23 | uri node['threatstack']['repo']['url'] 24 | distribution node['threatstack']['repo']['dist'] 25 | components node['threatstack']['repo']['components'] 26 | key node['threatstack']['repo']['key'] 27 | action :add 28 | end 29 | -------------------------------------------------------------------------------- /recipes/default.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Cookbook:: threatstack 3 | # Recipe:: default 4 | # 5 | # Copyright:: 2014-2020, Threat Stack 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | # 20 | # == This recipe will install the tsagent and start the service. 21 | # == It supports agent versions >= 2.0. For previous versions of 22 | # == the agent, refer to older versions of this cookbook, tagged 23 | # == in the git repo. 24 | 25 | unless node['threatstack']['version'].nil? 26 | if node['threatstack']['version'].start_with?('1.') 27 | error_string = "Deprecation Error: Unsupported agent version detected ( #{node['threatstack']['version']} ).\n" 28 | error_string += 'For agent versions < 2.0, use a previous version of this cookbook.' 29 | raise NotImplementedError, error_string 30 | end 31 | end 32 | 33 | if node['threatstack']['repo_enable'] 34 | if platform_family?('fedora', 'amazon') 35 | include_recipe 'threatstack::rhel' 36 | else 37 | include_recipe "threatstack::#{node['platform_family']}" 38 | end 39 | end 40 | 41 | # Disable auditd on amazon linux 2, RHEL, and CentOS. This used to 42 | # be a couple exec blocks because we hit a wall with this issue fairly 43 | # early, but this is a little cleaner. 44 | service 'auditd' do 45 | action %w(stop disable) 46 | stop_command 'service auditd stop' 47 | end 48 | 49 | package 'threatstack-agent' do 50 | version node['threatstack']['version'] if node['threatstack']['version'] 51 | if node['threatstack']['version'].nil? 52 | action :upgrade 53 | else 54 | action :install 55 | end 56 | end 57 | 58 | include_recipe 'threatstack::agent_setup' unless node['threatstack']['install_only'] == true 59 | -------------------------------------------------------------------------------- /recipes/rhel.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Cookbook:: threatstack 3 | # Recipe:: rhel 4 | # 5 | # Copyright:: 2014-2020, Threat Stack 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | remote_file node['threatstack']['repo']['key_file'] do 20 | source node['threatstack']['repo']['key'] 21 | owner 'root' 22 | group 'root' 23 | mode '0644' 24 | action :create 25 | end 26 | 27 | yum_repository 'threatstack' do 28 | description 'Threat Stack Package Repository' 29 | baseurl node['threatstack']['repo']['url'] 30 | gpgkey node['threatstack']['repo']['key_file_uri'] 31 | gpgcheck node['threatstack']['validate_gpg_key'] 32 | action :add 33 | end 34 | -------------------------------------------------------------------------------- /spec/default_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'threatstack::default' do 4 | context 'single-ruleset-test' do 5 | let(:chef_run) do 6 | ChefSpec::SoloRunner.new do |node| 7 | node.normal['threatstack']['rulesets'] = ['Base Rule Set'] 8 | end.converge(described_recipe) 9 | end 10 | 11 | before do 12 | contents = { 'deploy_key' => 'ABCD1234' } 13 | stub_data_bag_item('threatstack', 'api_keys').and_return(contents) 14 | end 15 | 16 | it 'executes the ts setup' do 17 | expect(chef_run).to run_execute('tsagent setup').with( 18 | command: "tsagent setup --deploy-key=ABCD1234 --ruleset='Base Rule Set'" 19 | ) 20 | end 21 | end 22 | 23 | context '1.x version' do 24 | let(:chef_run) do 25 | ChefSpec::SoloRunner.new do |node| 26 | node.normal['threatstack']['rulesets'] = ['Base Rule Set'] 27 | node.normal['threatstack']['version'] = '1.9.0ubuntuBlergh' 28 | end 29 | end 30 | 31 | before do 32 | contents = { 'deploy_key' => 'ABCD1234' } 33 | stub_data_bag_item('threatstack', 'api_keys').and_return(contents) 34 | end 35 | 36 | it 'should raise a cookbook deprecation error for agent 1.x' do 37 | # Error message should say something about deprecation and the agent version 38 | expect{ chef_run.converge(described_recipe) } .to raise_error(NotImplementedError, /Deprecation.*agent version/) 39 | end 40 | end 41 | 42 | context '2.x version' do 43 | let(:chef_run) do 44 | ChefSpec::SoloRunner.new do |node| 45 | node.normal['threatstack']['rulesets'] = ['Base Rule Set'] 46 | node.normal['threatstack']['version'] = '2.blahblah' 47 | end 48 | end 49 | 50 | before do 51 | contents = { 'deploy_key' => 'ABCD1234' } 52 | stub_data_bag_item('threatstack', 'api_keys').and_return(contents) 53 | end 54 | 55 | it 'should NOT raise a cookbook deprecation error for agent 2.x' do 56 | # Error message should say something about deprecation and the agent version 57 | expect{ chef_run.converge(described_recipe) } .not_to raise_error 58 | end 59 | end 60 | 61 | context 'explicit-deploy-key' do 62 | let(:chef_run) do 63 | ChefSpec::SoloRunner.new do |node| 64 | node.normal['threatstack']['deploy_key'] = 'EFGH5678' 65 | node.normal['threatstack']['rulesets'] = ['Base Rule Set'] 66 | end.converge(described_recipe) 67 | end 68 | 69 | it 'prefers the explicit deploy_key when one is specified' do 70 | expect(chef_run).to run_execute('tsagent setup').with( 71 | command: "tsagent setup --deploy-key=EFGH5678 --ruleset='Base Rule Set'" 72 | ) 73 | end 74 | end 75 | 76 | context 'multi-ruleset-test' do 77 | let(:chef_run) do 78 | ChefSpec::SoloRunner.new do |node| 79 | node.normal['threatstack']['deploy_key'] = 'ABCD1234' 80 | node.normal['threatstack']['rulesets'] = ['Base Rule Set', 'CloudTrail Base Rule Set'] 81 | end.converge(described_recipe) 82 | end 83 | 84 | it 'executes the tsagent setup with multiple rulesets' do 85 | expect(chef_run).to run_execute('tsagent setup').with( 86 | command: "tsagent setup --deploy-key=ABCD1234 --ruleset='Base Rule Set,CloudTrail Base Rule Set'" 87 | ) 88 | end 89 | end 90 | 91 | context 'enable-containers' do 92 | let(:chef_run) do 93 | ChefSpec::SoloRunner.new do |node| 94 | node.normal['threatstack']['enable_containers'] = true 95 | node.normal['threatstack']['deploy_key'] = 'ABCD1234' 96 | end.converge(described_recipe) 97 | end 98 | 99 | it 'enables container observation via tsagent config' do 100 | expect(chef_run).to render_file('/opt/threatstack/etc/chef_args_cache.txt').with_content( 101 | 'tsagent config --set enable_containers 1;' 102 | ) 103 | end 104 | end 105 | 106 | context 'dont-enable-containers-when-attr-false' do 107 | let(:chef_run) do 108 | ChefSpec::SoloRunner.new do |node| 109 | node.normal['threatstack']['enable_containers'] = false 110 | node.normal['threatstack']['deploy_key'] = 'ABCD1234' 111 | end.converge(described_recipe) 112 | end 113 | 114 | it 'doesnt enable container observation when attr is false' do 115 | expect(chef_run).to_not render_file('/opt/threatstack/etc/chef_args_cache.txt').with_content( 116 | 'tsagent config --set enable_containers 1;' 117 | ) 118 | end 119 | end 120 | 121 | context 'dont-enable-containers-when-attr-nil' do 122 | let(:chef_run) do 123 | ChefSpec::SoloRunner.new do |node| 124 | node.normal['threatstack']['enable_containers'] = nil 125 | node.normal['threatstack']['deploy_key'] = 'ABCD1234' 126 | end.converge(described_recipe) 127 | end 128 | 129 | it 'doesnt enable container observation when attr nil' do 130 | expect(chef_run).to_not render_file('/opt/threatstack/etc/chef_args_cache.txt').with_content( 131 | 'tsagent config --set enable_containers 1;' 132 | ) 133 | end 134 | end 135 | 136 | 137 | context 'agent-extra-args' do 138 | let(:chef_run) do 139 | ChefSpec::SoloRunner.new do |node| 140 | node.normal['threatstack']['deploy_key'] = 'ABCD1234' 141 | node.normal['threatstack']['agent_config_args'] = ['foo 1', 'bar 1'] 142 | end.converge(described_recipe) 143 | end 144 | 145 | it 'sets tsagent config' do 146 | expect(chef_run).to render_file('/opt/threatstack/etc/chef_args_cache.txt').with_content( 147 | 'tsagent config --set foo 1; tsagent config --set bar 1;' 148 | ) 149 | end 150 | 151 | it 'notifies tsagent config from the file resource' do 152 | args_file = chef_run.file('/opt/threatstack/etc/chef_args_cache.txt') 153 | expect(args_file).to notify('execute[tsagent config]') 154 | end 155 | 156 | it 'still runs setup' do 157 | expect(chef_run).to run_execute('tsagent setup').with( 158 | command: "tsagent setup --deploy-key=ABCD1234" 159 | ) 160 | end 161 | end 162 | 163 | context 'no agent-extra-args' do 164 | let(:chef_run) do 165 | ChefSpec::SoloRunner.new do |node| 166 | node.normal['threatstack']['deploy_key'] = 'ABCD1234' 167 | end.converge(described_recipe) 168 | end 169 | 170 | it 'does not write to config cache file' do 171 | expect(chef_run).to_not render_file('/opt/threatstack/etc/chef_args_cache.txt') 172 | end 173 | 174 | it 'does not run tsagent config by default' do 175 | expect(chef_run).to_not run_execute('tsagent config') 176 | end 177 | 178 | it 'still runs setup' do 179 | expect(chef_run).to run_execute('tsagent setup').with( 180 | command: "tsagent setup --deploy-key=ABCD1234" 181 | ) 182 | end 183 | end 184 | 185 | context 'install only' do 186 | let(:chef_run) do 187 | ChefSpec::SoloRunner.new do |node| 188 | node.normal['threatstack']['deploy_key'] = 'ABCD1234' 189 | node.normal['threatstack']['install_only'] = true 190 | end.converge(described_recipe) 191 | end 192 | 193 | it 'does not write to config cache file' do 194 | expect(chef_run).to_not render_file('/opt/threatstack/etc/chef_args_cache.txt') 195 | end 196 | 197 | it 'does not run tsagent config by default' do 198 | expect(chef_run).to_not run_execute('tsagent config') 199 | end 200 | 201 | it 'does not run setup' do 202 | expect(chef_run).to_not run_execute('tsagent setup').with( 203 | command: "tsagent setup --deploy-key=ABCD1234" 204 | ) 205 | end 206 | 207 | it 'still installs the agent' do 208 | expect(chef_run).to upgrade_package('threatstack-agent') 209 | end 210 | end 211 | 212 | context 'hostname-test' do 213 | let(:chef_run) do 214 | ChefSpec::SoloRunner.new do |node| 215 | node.normal['threatstack']['deploy_key'] = 'ABCD1234' 216 | node.normal['threatstack']['hostname'] = 'test_server-i-abc123' 217 | end.converge(described_recipe) 218 | end 219 | 220 | it 'executes the tsagent setup with a configured hostname' do 221 | expect(chef_run).to run_execute('tsagent setup').with( 222 | command: "tsagent setup --deploy-key=ABCD1234 --hostname='test_server-i-abc123'" 223 | ) 224 | end 225 | end 226 | 227 | context 'upgrade-apt-package when no version is specified' do 228 | let(:chef_run) do 229 | ChefSpec::SoloRunner.new( 230 | platform: 'ubuntu', 231 | version: '16.04' 232 | ) do |node| 233 | node.normal['threatstack']['deploy_key'] = 'ABCD1234' 234 | end.converge(described_recipe) 235 | end 236 | 237 | it 'installs or upgrades the threatstack-agent package on ubuntu' do 238 | expect(chef_run).to upgrade_package('threatstack-agent') 239 | end 240 | end 241 | 242 | context 'install-apt-package when specific version is specified' do 243 | let(:chef_run) do 244 | ChefSpec::SoloRunner.new( 245 | platform: 'ubuntu', 246 | version: '18.04' 247 | ) do |node| 248 | node.normal['threatstack']['deploy_key'] = 'ABCD1234' 249 | node.normal['threatstack']['version'] = '2.0.0.0ubuntu18.56' 250 | end.converge(described_recipe) 251 | end 252 | 253 | it 'installs the threatstack-agent package on ubuntu' do 254 | expect(chef_run).to install_package('threatstack-agent') 255 | end 256 | end 257 | 258 | context 'upgrade-yum-package when no version is specified' do 259 | let(:chef_run) do 260 | ChefSpec::SoloRunner.new( 261 | platform: 'redhat', 262 | version: '7.4' 263 | ) do |node| 264 | node.normal['threatstack']['deploy_key'] = 'ABCD1234' 265 | end.converge(described_recipe) 266 | end 267 | 268 | it 'installs the threatstack-agent package on redhat' do 269 | expect(chef_run).to upgrade_package('threatstack-agent') 270 | end 271 | end 272 | end 273 | -------------------------------------------------------------------------------- /spec/repo_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'threatstack::default' do 4 | 5 | context 'debian-jessie' do 6 | let(:chef_run) do 7 | runner = ChefSpec::SoloRunner.new( 8 | platform: 'debian', 9 | version: '8.11' 10 | ) do |node| 11 | node.normal['threatstack']['deploy_key'] = 'ABCD1234' 12 | end 13 | runner.converge(described_recipe) 14 | end 15 | 16 | it 'installs the apt-transport-http package' do 17 | expect(chef_run).to install_package('apt-transport-https') 18 | end 19 | 20 | it 'sets up the apt repository' do 21 | expect(chef_run).to add_apt_repository('threatstack').with( 22 | distribution: 'jessie' 23 | ) 24 | end 25 | end 26 | 27 | context 'debian-stretch' do 28 | let(:chef_run) do 29 | runner = ChefSpec::SoloRunner.new( 30 | platform: 'debian', 31 | version: '9.12' 32 | ) do |node| 33 | node.normal['threatstack']['deploy_key'] = 'ABCD1234' 34 | end 35 | runner.converge(described_recipe) 36 | end 37 | 38 | it 'installs the apt-transport-http package' do 39 | expect(chef_run).to install_package('apt-transport-https') 40 | end 41 | 42 | it 'sets up the apt repository' do 43 | expect(chef_run).to add_apt_repository('threatstack').with( 44 | distribution: 'stretch' 45 | ) 46 | end 47 | end 48 | 49 | context 'ubuntu-xenial' do 50 | let(:chef_run) do 51 | runner = ChefSpec::SoloRunner.new( 52 | platform: 'ubuntu', 53 | version: '16.04' 54 | ) do |node| 55 | node.normal['threatstack']['deploy_key'] = 'ABCD1234' 56 | end 57 | runner.converge(described_recipe) 58 | end 59 | 60 | it 'sets up the apt repository' do 61 | expect(chef_run).to add_apt_repository('threatstack').with( 62 | distribution: 'xenial' 63 | ) 64 | end 65 | end 66 | 67 | context 'ubuntu-bionic' do 68 | let(:chef_run) do 69 | runner = ChefSpec::SoloRunner.new( 70 | platform: 'ubuntu', 71 | version: '18.04' 72 | ) do |node| 73 | node.normal['threatstack']['deploy_key'] = 'ABCD1234' 74 | end 75 | runner.converge(described_recipe) 76 | end 77 | 78 | it 'sets up the apt repository' do 79 | expect(chef_run).to add_apt_repository('threatstack').with( 80 | distribution: 'bionic' 81 | ) 82 | end 83 | 84 | it 'doesnt worry about auditd' do 85 | expect(chef_run).to_not run_execute('stop_auditd') 86 | expect(chef_run).to_not run_execute('disable_auditd') 87 | end 88 | end 89 | 90 | context 'redhat' do 91 | let(:chef_run) do 92 | runner = ChefSpec::SoloRunner.new( 93 | platform: 'redhat', 94 | version: '7.8' 95 | ) do |node| 96 | node.normal['threatstack']['deploy_key'] = 'ABCD1234' 97 | end 98 | runner.converge(described_recipe) 99 | end 100 | 101 | it 'downloads the threatstack repo key' do 102 | expect(chef_run).to create_remote_file('/etc/pki/rpm-gpg/RPM-GPG-KEY-THREATSTACK') 103 | end 104 | 105 | it 'sets up the yum repository' do 106 | expect(chef_run).to add_yum_repository('threatstack').with( 107 | description: 'Threat Stack Package Repository', 108 | baseurl: 'https://pkg.threatstack.com/v2/EL/7', 109 | gpgkey: 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-THREATSTACK' 110 | ) 111 | end 112 | 113 | it 'stops and disables auditd' do 114 | expect(chef_run).to stop_service('auditd') 115 | end 116 | end 117 | 118 | context 'centos' do 119 | let(:chef_run) do 120 | runner = ChefSpec::SoloRunner.new( 121 | platform: 'centos', 122 | version: '7.8.2003' 123 | ) do |node| 124 | node.normal['threatstack']['deploy_key'] = 'ABCD1234' 125 | end 126 | runner.converge(described_recipe) 127 | end 128 | 129 | it 'downloads the threatstack repo key' do 130 | expect(chef_run).to create_remote_file('/etc/pki/rpm-gpg/RPM-GPG-KEY-THREATSTACK') 131 | end 132 | 133 | it 'sets up the yum repository' do 134 | expect(chef_run).to add_yum_repository('threatstack').with( 135 | description: 'Threat Stack Package Repository', 136 | baseurl: 'https://pkg.threatstack.com/v2/EL/7', 137 | gpgkey: 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-THREATSTACK' 138 | ) 139 | end 140 | end 141 | 142 | context 'amazon linux 1' do 143 | let(:chef_run) do 144 | runner = ChefSpec::SoloRunner.new( 145 | platform: 'amazon', 146 | version: '2018.03' 147 | ) do |node| 148 | node.normal['threatstack']['deploy_key'] = 'ABCD1234' 149 | end 150 | runner.converge(described_recipe) 151 | end 152 | 153 | it 'downloads the threatstack repo key' do 154 | expect(chef_run).to create_remote_file('/etc/pki/rpm-gpg/RPM-GPG-KEY-THREATSTACK') 155 | end 156 | 157 | it 'sets up the yum repository' do 158 | expect(chef_run).to add_yum_repository('threatstack').with( 159 | description: 'Threat Stack Package Repository', 160 | baseurl: 'https://pkg.threatstack.com/v2/Amazon/1', 161 | gpgkey: 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-THREATSTACK' 162 | ) 163 | end 164 | end 165 | 166 | context 'amazon linux 2' do 167 | let(:chef_run) do 168 | runner = ChefSpec::SoloRunner.new( 169 | platform: 'amazon', 170 | version: '2' 171 | ) do |node| 172 | node.normal['threatstack']['deploy_key'] = 'ABCD1234' 173 | end 174 | runner.converge(described_recipe) 175 | end 176 | 177 | it 'downloads the threatstack repo key' do 178 | expect(chef_run).to create_remote_file('/etc/pki/rpm-gpg/RPM-GPG-KEY-THREATSTACK') 179 | end 180 | 181 | it 'sets up the yum repository' do 182 | expect(chef_run).to add_yum_repository('threatstack').with( 183 | description: 'Threat Stack Package Repository', 184 | baseurl: 'https://pkg.threatstack.com/v2/Amazon/2', 185 | gpgkey: 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-THREATSTACK' 186 | ) 187 | end 188 | it 'stops and disables auditd' do 189 | expect(chef_run).to stop_service('auditd') 190 | end 191 | 192 | end 193 | end 194 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # spec_helper.rb 2 | require 'chefspec' 3 | 4 | RSpec.configure do |config| 5 | config.platform = 'ubuntu' 6 | config.version = '20.04' 7 | end 8 | 9 | ChefSpec::Coverage.start! 10 | require 'chefspec/berkshelf' 11 | -------------------------------------------------------------------------------- /test/cookbooks/install_old_agent/attributes/default.rb: -------------------------------------------------------------------------------- 1 | default['threatstack']['old_version'] = '2.1.3' 2 | default['threatstack']['version'] = '2.3.0' 3 | -------------------------------------------------------------------------------- /test/cookbooks/install_old_agent/attributes/repo.rb: -------------------------------------------------------------------------------- 1 | default['threatstack']['repo_enable'] = true 2 | default['threatstack']['old_agent']['validate_gpg_key'] = true 3 | default['threatstack']['old_agent']['repo']['components'] = ['main'] 4 | 5 | case node['platform_family'] 6 | when 'debian' 7 | default['threatstack']['old_agent']['repo']['dist'] = node['lsb']['codename'] 8 | default['threatstack']['old_agent']['repo']['url'] = 'https://pkg.threatstack.com/v2/Ubuntu' 9 | default['threatstack']['old_agent']['repo']['key'] = 'https://app.threatstack.com/APT-GPG-KEY-THREATSTACK' 10 | when 'rhel', 'fedora', 'amazon' 11 | case node['platform'] 12 | when 'amazon' 13 | if node['platform_version'] == '2' 14 | default['threatstack']['old_agent']['repo']['url'] = 'https://pkg.threatstack.com/v2/Amazon/2' 15 | else 16 | default['threatstack']['old_agent']['repo']['url'] = 'https://pkg.threatstack.com/v2/Amazon/1' 17 | end 18 | when 'centos', 'redhat' 19 | default['threatstack']['old_agent']['repo']['url'] = "https://pkg.threatstack.com/v2/EL/#{node['platform_version'].to_i}" 20 | else 21 | default['threatstack']['old_agent']['repo']['url'] = 'https://pkg.threatstack.com/v2/EL/7' 22 | end 23 | default['threatstack']['old_agent']['repo']['key'] = 'https://app.threatstack.com/RPM-GPG-KEY-THREATSTACK' 24 | default['threatstack']['old_agent']['repo']['key_file'] = '/etc/pki/rpm-gpg/RPM-GPG-KEY-THREATSTACK' 25 | default['threatstack']['old_agent']['repo']['key_file_uri'] = 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-THREATSTACK' 26 | end 27 | -------------------------------------------------------------------------------- /test/cookbooks/install_old_agent/metadata.rb: -------------------------------------------------------------------------------- 1 | name 'install_old_agent' 2 | maintainer 'Threat Stack, Inc' 3 | maintainer_email 'support@threatstack.com' 4 | license 'Apache-2.0' 5 | description 'A test cookbook to prepare the test environment for: tests' 6 | version '0.0.1' 7 | -------------------------------------------------------------------------------- /test/cookbooks/install_old_agent/recipes/default.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Cookbook:: install_old_agent 3 | # Recipe:: default 4 | # 5 | # Copyright:: 2014-2020, Threat Stack 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | # Just install old agent, don't fire it up. 20 | if node['threatstack']['repo_enable'] 21 | if platform_family?('rhel', 'fedora', 'amazon') 22 | remote_file node['threatstack']['old_agent']['repo']['key_file'] do 23 | source node['threatstack']['old_agent']['repo']['key'] 24 | owner 'root' 25 | group 'root' 26 | mode '0644' 27 | action :create 28 | end 29 | 30 | yum_repository 'threatstack-old-agent' do 31 | description 'Threat Stack Package Repository' 32 | baseurl node['threatstack']['old_agent']['repo']['url'] 33 | gpgkey node['threatstack']['old_agent']['repo']['key_file_uri'] 34 | gpgcheck node['threatstack']['old_agent']['validate_gpg_key'] 35 | action :add 36 | end 37 | else 38 | package 'apt-transport-https' 39 | 40 | apt_repository 'threatstack-old-agent' do 41 | uri node['threatstack']['old_agent']['repo']['url'] 42 | distribution node['threatstack']['old_agent']['repo']['dist'] 43 | components node['threatstack']['old_agent']['repo']['components'] 44 | key node['threatstack']['old_agent']['repo']['key'] 45 | action :add 46 | end 47 | end 48 | end 49 | 50 | execute 'stop_auditd' do 51 | command 'service auditd stop' 52 | only_if { platform?('amazon') && node['platform_version'] == '2' || platform?('centos', 'redhat') } 53 | end 54 | 55 | execute 'disable_auditd' do 56 | command 'systemctl disable auditd' 57 | only_if { platform?('amazon') && node['platform_version'] == '2' || platform?('centos', 'redhat') } 58 | end 59 | 60 | # Change this as more agent versions are released, in accordance with official support 61 | # Hacky version logic to deal with debian systems 62 | package 'threatstack-agent' do 63 | version platform_family?('rhel', 'fedora', 'amazon') ? node['threatstack']['old_version'] : node['threatstack']['old_version'] + '*' 64 | action :install 65 | notifies :run, 'execute[stop_auditd]', :before 66 | notifies :run, 'execute[disable_auditd]', :before 67 | end 68 | 69 | # How we can verify what is installed is what is defined to be installed 70 | # See: http://www.hurryupandwait.io/blog/accessing-chef-node-attributes-from-kitchen-tests 71 | ruby_block 'Save node attributes' do 72 | block do 73 | if Dir.exist?('/tmp/') 74 | IO.write('/tmp/chef_node_for_tests.json', node.to_json) 75 | end 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /test/cookbooks/setup/README.md: -------------------------------------------------------------------------------- 1 | # setup cookbook 2 | 3 | # Requirements 4 | 5 | Requires the `threatstack` cookbook. 6 | 7 | # Usage 8 | 9 | This cookbook is only used to test the `threatstack` cookbook. 10 | 11 | # Attributes 12 | 13 | none 14 | 15 | # Recipes 16 | 17 | ## default 18 | 19 | Forces apt update to run. Don't want to put that into the recipe proper if we can help it -- so the chef server admin can set the pace on that; put it here just for tests. 20 | 21 | 22 | # Author 23 | 24 | Author:: Threat Stack, Inc. () -------------------------------------------------------------------------------- /test/cookbooks/setup/metadata.rb: -------------------------------------------------------------------------------- 1 | name 'setup' 2 | maintainer 'Threat Stack, Inc' 3 | maintainer_email 'support@threatstack.com' 4 | license 'Apache-2.0' 5 | description 'A test cookbook to prepare the test environment for: tests' 6 | version '0.0.1' 7 | -------------------------------------------------------------------------------- /test/cookbooks/setup/recipes/default.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Cookbook:: setup 3 | # Recipe:: default 4 | # 5 | # Copyright:: 2014-2020, Threat Stack 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | # Set up tests to run apt update. It's not run as part of 20 | # default threatstack recipe so that companies can decide 21 | # how often to run it on their own. 22 | apt_update unless platform_family?('rhel', 'fedora', 'amazon') 23 | -------------------------------------------------------------------------------- /test/integration/custom/serverspec/default_spec.rb: -------------------------------------------------------------------------------- 1 | require 'serverspec' 2 | 3 | set :backend, :exec 4 | 5 | describe package('threatstack-agent') do 6 | it { should be_installed } 7 | end 8 | 9 | # Work around old service system in Amazon Linux 1 10 | if os[:family] == 'amazon' && os[:release] != "2" 11 | 12 | describe command('sudo initctl status threatstack') do 13 | its(:stdout) { should match /threatstack start\/running/ } # rubocop: disable Lint/AmbiguousRegexpLiteral 14 | end 15 | 16 | describe service('threatstack') do 17 | it { should be_enabled } 18 | end 19 | else 20 | describe service('threatstack') do 21 | it { should be_running } 22 | it { should be_enabled } 23 | end 24 | end 25 | 26 | describe command('tsagent config --list') do 27 | its(:stdout) { should match /log.maxSize=22/ } # rubocop: disable Lint/AmbiguousRegexpLiteral 28 | end 29 | -------------------------------------------------------------------------------- /test/integration/data_bags/insecure_data_bag_secret: -------------------------------------------------------------------------------- 1 | h3Lf5h26GOfW3X2Cwm/7rQA46AD8m4ncYl8IgmCaSRYglAB3UuTYyjoFFsA2gGFe 2 | p7uvYg1hLHst+6KWhXXIYB3G9XezUGa8uSPLFDzqQWCZHKWzZ5TstWt7i9jes7eR 3 | QohWbflQJoX0tvqgwjkx2teEDgcjegABd9dTVHJ2nql42e0AsLeuU6ZyDI+AgOwu 4 | DXkn7Eno2m4B58wckgxhKl4cpi5CEZNUOUrJ+IfxX5tmdvad5J3Co+t74NfzzK2C 5 | OJMOMiSH+zmJsKdhpLYQP8kgNTSY3zw2r12UGydIWQC+8VX5uSJCJqmjNxhd9Etq 6 | Mx+dMRh3t7eZfrrbqyzVlOCK8+f5bkoT2AcbFbn7ZPRU/3x1Ury9gwC+EJ3fBgFq 7 | ZQn1/a1Dxxlpv+to2i9irZD9JaHbes0yM9Q/RUZtNEraRjMzYCk+kQBFPTDLg0Gy 8 | MEUJxHYh1nkY9D/2KYLshKcXjn9WBEZDGBCT3/hOdLGBIJXYEG3zfEYw9v66vNAy 9 | iXOnEGzQdU6xkJlFTHiPvItrW3FQ14kXkf9ofGOG6NsXwmLFquRzQxoxL2kuqxe3 10 | Qni+jfz7x6f9KlV+0ZFeeoP5nd3Fx2TKCMK5j0PWVoWaYxCtUsZGBHYkuxW/mqAb 11 | S4O96KlbyNcSozdyXZa7vwyWFg4TcATpPhovcT8yN7c= 12 | -------------------------------------------------------------------------------- /test/integration/data_bags/threatstack/api_keys.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "api_keys", 3 | "deploy_key": { 4 | "encrypted_data": "qwwau017/cxUjbiVYJ8MxKmtrXRFEO6itpBtYc213PU=\n", 5 | "hmac": "jqLdvi5gqQ0FylZrqK2+q+IEJv30hRnrFAjKQFN3e3Q=\n", 6 | "iv": "v0mStikWnMsS0aXCcKsKaw==\n", 7 | "version": 2, 8 | "cipher": "aes-256-cbc" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/integration/default/serverspec/default_spec.rb: -------------------------------------------------------------------------------- 1 | require 'serverspec' 2 | 3 | set :backend, :exec 4 | 5 | describe package('threatstack-agent') do 6 | it { should be_installed } 7 | end 8 | 9 | # Work around old service system in Amazon Linux 1 10 | if os[:family] == 'amazon' && os[:release] != "2" 11 | 12 | describe command('sudo initctl status threatstack') do 13 | its(:stdout) { should match /threatstack start\/running/ } # rubocop: disable Lint/AmbiguousRegexpLiteral 14 | end 15 | 16 | describe service('threatstack') do 17 | it { should be_enabled } 18 | end 19 | else 20 | describe service('threatstack') do 21 | it { should be_running } 22 | it { should be_enabled } 23 | end 24 | end 25 | 26 | describe command('tsagent status') do 27 | # Sometimes due to other services, like auditd, the install would be successful, but then this service would get killed 28 | its(:stdout) { should match /UP Threat Stack Agent Daemon/ } # rubocop: disable Lint/AmbiguousRegexpLiteral 29 | its(:stdout) { should match /UP Threat Stack Backend Connection/ } # rubocop: disable Lint/AmbiguousRegexpLiteral 30 | its(:stdout) { should match /UP Threat Stack Heartbeat Service/ } # rubocop: disable Lint/AmbiguousRegexpLiteral 31 | its(:stdout) { should match /UP Threat Stack Login Collector/ } # rubocop: disable Lint/AmbiguousRegexpLiteral 32 | its(:stdout) { should match /UP Threat Stack Log Scan Service/ } # rubocop: disable Lint/AmbiguousRegexpLiteral 33 | its(:stdout) { should match /UP Threat Stack Vulnerability Scanner/ } # rubocop: disable Lint/AmbiguousRegexpLiteral 34 | its(:stdout) { should match /UP Threat Stack File Integrity Monitor/ } # rubocop: disable Lint/AmbiguousRegexpLiteral 35 | end 36 | -------------------------------------------------------------------------------- /test/integration/upgrades/serverspec/default_spec.rb: -------------------------------------------------------------------------------- 1 | require 'serverspec' 2 | 3 | set :backend, :exec 4 | 5 | # Version to expect on install. Change this when we bump versions 6 | current_version = '2.3.2' 7 | 8 | describe package('threatstack-agent') do 9 | it { should be_installed } 10 | end 11 | 12 | # Check version 13 | describe 'package version' do 14 | # How we can verify what is installed is what is defined to be installed 15 | # 16 | # IMPORTANT: Must set node.override['threatstack']['version'] in 17 | # `test/cookbooks/install_old_agent/attributes/default.rb` for test to pass! 18 | # 19 | # See: http://www.hurryupandwait.io/blog/accessing-chef-node-attributes-from-kitchen-tests 20 | let(:node) { JSON.parse(IO.read('/tmp/chef_node_for_tests.json')) } 21 | let(:current_version) { node['threatstack'] } 22 | 23 | it 'is running the current version' do 24 | if os[:family] == 'ubuntu' 25 | expect(command("dpkg-query -f '${Status} ${Version}' -W threatstack-agent").stdout).to match("^(install|hold) ok installed #{current_version}.*$") 26 | elsif os[:family] == 'redhat' 27 | expect(command("repoquery --qf '%{version}' threatstack-agent").stdout.strip).to eq(current_version) # rubocop: disable Style/FormatStringToken 28 | end 29 | end 30 | end 31 | 32 | # Work around old service system in Amazon Linux 1 33 | if os[:family] == 'amazon' && os[:release] != "2" 34 | 35 | describe command('sudo initctl status threatstack') do 36 | its(:stdout) { should match /threatstack start\/running/ } # rubocop: disable Lint/AmbiguousRegexpLiteral 37 | end 38 | 39 | describe service('threatstack') do 40 | it { should be_enabled } 41 | end 42 | else 43 | describe service('threatstack') do 44 | it { should be_running } 45 | it { should be_enabled } 46 | end 47 | end 48 | 49 | describe command('tsagent status') do 50 | # Sometimes due to other services, like auditd, the install would be successful, but then this service would get killed 51 | its(:stdout) { should match /UP Threat Stack Agent Daemon/ } # rubocop: disable Lint/AmbiguousRegexpLiteral 52 | its(:stdout) { should match /UP Threat Stack Backend Connection/ } # rubocop: disable Lint/AmbiguousRegexpLiteral 53 | its(:stdout) { should match /UP Threat Stack Heartbeat Service/ } # rubocop: disable Lint/AmbiguousRegexpLiteral 54 | its(:stdout) { should match /UP Threat Stack Login Collector/ } # rubocop: disable Lint/AmbiguousRegexpLiteral 55 | its(:stdout) { should match /UP Threat Stack Log Scan Service/ } # rubocop: disable Lint/AmbiguousRegexpLiteral 56 | its(:stdout) { should match /UP Threat Stack Vulnerability Scanner/ } # rubocop: disable Lint/AmbiguousRegexpLiteral 57 | its(:stdout) { should match /UP Threat Stack File Integrity Monitor/ } # rubocop: disable Lint/AmbiguousRegexpLiteral 58 | end 59 | --------------------------------------------------------------------------------