diff --git a/.gitignore b/.gitignore index 482d7a5..dac7d67 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -Gemfile.lock .bundle/** .aws-sam/** packaged-template.yaml diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..b617bcb --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,48 @@ +GEM + remote: https://rubygems.org/ + specs: + cfn-model (0.4.0) + kwalify (= 0.7.2) + psych (~> 3) + cfn-nag (0.4.35) + cfn-model (= 0.4.0) + colorize (= 0.8.1) + jmespath (~> 1.3.1) + logging (~> 2.2.2) + netaddr (~> 1.5.1) + trollop (~> 2.1.2) + colorize (0.8.1) + ffi (1.11.1) + jmespath (1.3.1) + kwalify (0.7.2) + little-plugger (1.1.4) + logging (2.2.2) + little-plugger (~> 1.1) + multi_json (~> 1.10) + multi_json (1.13.1) + mustermann (1.0.3) + netaddr (1.5.1) + psych (3.1.0) + rack (2.0.7) + rack-protection (2.0.5) + rack + rbnacl (7.0.0) + ffi + sinatra (2.0.5) + mustermann (~> 1.0) + rack (~> 2.0) + rack-protection (= 2.0.5) + tilt (~> 2.0) + tilt (2.0.9) + trollop (2.1.3) + +PLATFORMS + ruby + +DEPENDENCIES + cfn-nag + rbnacl + sinatra + +BUNDLED WITH + 2.0.2 diff --git a/README.md b/README.md index 167f45f..b4e85ae 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,15 @@ ## CfnNagService -This repository contains the automation code required to deploy https://github.com/stelligent/cfn_nag as an API Gateway endpoint. +This repository contains the automation code required to deploy https://github.com/stelligent/cfn_nag as either an API Gateway endpoint +or as a Docker container. ### Endpoints -Each request expects a JSON structure with a single `template_body` key. The value of this key should be a Base64 encoded CloudFormation template in either JSON or YAML. +Each request expects a CloudFormation template in either JSON or YAML. #### /scan -This endpoint returns the same response that you would see if you just ran `cfn_nag` from the command line. - -Request example: - -``` -{ - "template_body": "ewogICJBV1NUZW1wbGF0ZUZvcm1hdFZlcnNpb24iOiAiMjAxMC0wOS0wOSIsCiAgIlJlc291cmNlcyI6IHsKICAgICAgICAiUzNCdWNrZXQiOiB7CiAgICAgICAgICAgICJUeXBlIjogIkFXUzo6UzM6OkJ1Y2tldCIsCiAgICAgICAgICAgICJQcm9wZXJ0aWVzIjogewogICAgICAgICAgICAgICAgIkFjY2Vzc0NvbnRyb2wiOiAiUHVibGljUmVhZFdyaXRlIiwKICAgICAgICAgICAgICAgICJDb3JzQ29uZmlndXJhdGlvbiI6IHsKICAgICAgICAgICAgICAgICAgICAiQ29yc1J1bGVzIjogWwogICAgICAgICAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQWxsb3dlZEhlYWRlcnMiOiBbCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIioiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFsbG93ZWRNZXRob2RzIjogWwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHRVQiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFsbG93ZWRPcmlnaW5zIjogWwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIqIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFeHBvc2VkSGVhZGVycyI6IFsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGF0ZSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSWQiOiAibXlDT1JTUnVsZUlkMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWF4QWdlIjogIjM2MDAiCiAgICAgICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBbGxvd2VkSGVhZGVycyI6IFsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAieC1hbXotKiIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQWxsb3dlZE1ldGhvZHMiOiBbCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRFTEVURSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQWxsb3dlZE9yaWdpbnMiOiBbCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImh0dHA6Ly93d3cuZXhhbXBsZTEuY29tIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaHR0cDovL3d3dy5leGFtcGxlMi5jb20iCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIkV4cG9zZWRIZWFkZXJzIjogWwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDb25uZWN0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2VydmVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGF0ZSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSWQiOiAibXlDT1JTUnVsZUlkMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWF4QWdlIjogIjE4MDAiCiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9LAogICAgIk91dHB1dHMiOiB7CiAgICAgICAgIkJ1Y2tldE5hbWUiOiB7CiAgICAgICAgICAgICJWYWx1ZSI6IHsKICAgICAgICAgICAgICAgICJSZWYiOiAiUzNCdWNrZXQiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgICJEZXNjcmlwdGlvbiI6ICJOYW1lIG9mIHRoZSBzYW1wbGUgQW1hem9uIFMzIGJ1Y2tldCB3aXRoIENPUlMgZW5hYmxlZC4iCiAgICAgICAgfQogICAgfQp9Cg==" -} -``` +This endpoint returns a similar response that you would see if you just ran `cfn_nag` from the command line. Response example: @@ -50,12 +43,9 @@ Response example: } ``` -#### /scan_secure +#### /signed_scan -This endpoint will provide a digital signature so you can verify the authenticity of the results. There are two SSM SecureString parameters involved: - -* /CfnNagService/signing_key - The key the service uses to sign requests -* /CfnNagService/verify_key - The key you can use to verify signatures +This endpoint will provide a digital signature so you can verify the authenticity of the results. Response example: @@ -88,129 +78,22 @@ Response example: } ] }, + "encoded_results": "FGSDFSDFW.....", "signature": "eKlzShFty5tCC/zXo3Cf7L0E0yCxdXejS7dAYauBc2s9eBoCfs9Lmd2AQcGR\nEwrSUzr43s+bUjqy/5Sum1JcCQ==\n" } ``` +The encoded_results are strict Base64 encoded of the original template body, the results/violations and the list of rules applied. +When verifying the payload, verify the signature of the encoded_results as Base64 (i.e. don't decode the encoded_results +before verifying) + #### /status This endpoint just provides a 200 HTTP response and a simple message to let you know the endpoint is up. -### Endpoint options +#### Variations Between Lambda/Docker -All endpoints have two parameters that can modify the response. When set to `true` it will provide more information in the response. - -* return_template - Returns the template_body that was originally passed in to the service -* return_rule - Returns an array of all rules that were applied - -Example endpoint request URL: - -https://dtulcqx04a.execute-api.us-east-1.amazonaws.com/Prod/scan_secure/?return_template=true&return_rules=true - -Example response: - -``` -{ - "results": { - "failure_count": 1, - "violations": [ - { - "id": "W35", - "type": "WARN", - "message": "S3 Bucket should have access logging configured", - "logical_resource_ids": [ - "S3Bucket" - ], - "line_numbers": [ - 5 - ] - }, - { - "id": "F14", - "type": "FAIL", - "message": "S3 Bucket should not have a public read-write acl", - "logical_resource_ids": [ - "S3Bucket" - ], - "line_numbers": [ - 5 - ] - } - ] - }, - "signature": "eKlzShFty5tCC/zXo3Cf7L0E0yCxdXejS7dAYauBc2s9eBoCfs9Lmd2AQcGR\nEwrSUzr43s+bUjqy/5Sum1JcCQ==\n", - "template": "ewogICJBV1NUZW1wbGF0ZUZvcm1hdFZlcnNpb24iOiAiMjAxMC0wOS0wOSIsCiAgIlJlc291cmNlcyI6IHsKICAgICAgICAiUzNCdWNrZXQiOiB7CiAgICAgICAgICAgICJUeXBlIjogIkFXUzo6UzM6OkJ1Y2tldCIsCiAgICAgICAgICAgICJQcm9wZXJ0aWVzIjogewogICAgICAgICAgICAgICAgIkFjY2Vzc0NvbnRyb2wiOiAiUHVibGljUmVhZFdyaXRlIiwKICAgICAgICAgICAgICAgICJDb3JzQ29uZmlndXJhdGlvbiI6IHsKICAgICAgICAgICAgICAgICAgICAiQ29yc1J1bGVzIjogWwogICAgICAgICAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQWxsb3dlZEhlYWRlcnMiOiBbCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIioiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFsbG93ZWRNZXRob2RzIjogWwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHRVQiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFsbG93ZWRPcmlnaW5zIjogWwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIqIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFeHBvc2VkSGVhZGVycyI6IFsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGF0ZSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSWQiOiAibXlDT1JTUnVsZUlkMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWF4QWdlIjogIjM2MDAiCiAgICAgICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBbGxvd2VkSGVhZGVycyI6IFsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAieC1hbXotKiIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQWxsb3dlZE1ldGhvZHMiOiBbCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRFTEVURSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQWxsb3dlZE9yaWdpbnMiOiBbCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImh0dHA6Ly93d3cuZXhhbXBsZTEuY29tIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaHR0cDovL3d3dy5leGFtcGxlMi5jb20iCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIkV4cG9zZWRIZWFkZXJzIjogWwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDb25uZWN0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2VydmVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGF0ZSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSWQiOiAibXlDT1JTUnVsZUlkMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWF4QWdlIjogIjE4MDAiCiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9LAogICAgIk91dHB1dHMiOiB7CiAgICAgICAgIkJ1Y2tldE5hbWUiOiB7CiAgICAgICAgICAgICJWYWx1ZSI6IHsKICAgICAgICAgICAgICAgICJSZWYiOiAiUzNCdWNrZXQiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgICJEZXNjcmlwdGlvbiI6ICJOYW1lIG9mIHRoZSBzYW1wbGUgQW1hem9uIFMzIGJ1Y2tldCB3aXRoIENPUlMgZW5hYmxlZC4iCiAgICAgICAgfQogICAgfQp9Cg==", - "rules": [ - "W34 WARN Batch Job Definition Container Properties should not have Privileged set to true", - "W1 WARN Specifying credentials in the template itself is probably not the safest thing", - "W10 WARN CloudFront Distribution should enable access logging", - "W32 WARN CodeBuild project should specify an EncryptionKey value", - "F37 FAIL DMS Endpoint must not be a plaintext string or a Ref to a NoEcho Parameter with a Default value.", - "F36 FAIL Directory Service Microsoft AD must not be a plaintext string or a Ref to a NoEcho Parameter with a Default value.", - "F31 FAIL DirectoryService::SimpleAD should use a parameter for password, with NoEcho", - "W33 WARN EC2 Subnet should not have MapPublicIpOnLaunch set to true", - "F32 FAIL EFS FileSystem should have encryption enabled", - "F1 FAIL EBS volume should have server-side encryption enabled", - "F25 FAIL ElastiCache ReplicationGroup should have encryption enabled for at rest", - "F33 FAIL ElastiCache ReplicationGroup should have encryption enabled for in transit", - "W26 WARN Elastic Load Balancer should have access logging enabled", - "W17 WARN IAM managed policy should not allow Allow+NotAction", - "W23 WARN IAM managed policy should not allow Allow+NotResource", - "F5 FAIL IAM managed policy should not allow * action", - "W13 WARN IAM managed policy should not allow * resource", - "W16 WARN IAM policy should not allow Allow+NotAction", - "W22 WARN IAM policy should not allow Allow+NotResource", - "F4 FAIL IAM policy should not allow * action", - "W12 WARN IAM policy should not allow * resource", - "W15 WARN IAM role should not allow Allow+NotAction", - "W14 WARN IAM role should not allow Allow+NotAction on trust permissions", - "F6 FAIL IAM role should not allow Allow+NotPrincipal in its trust policy", - "W21 WARN IAM role should not allow Allow+NotResource", - "F3 FAIL IAM role should not allow * action on its permissions policy", - "F2 FAIL IAM role should not allow * action on its trust policy", - "W11 WARN IAM role should not allow * resource on its permissions policy", - "F19 FAIL EnableKeyRotation should not be false or absent on KMS::Key resource", - "W24 WARN Lambda permission beside InvokeFunction might not be what you want? Not sure!?", - "F13 FAIL Lambda permission principal should not be wildcard", - "F12 FAIL IAM managed policy should not apply directly to users. Should be on group", - "F30 FAIL Neptune database cluster storage should have encryption enabled", - "F11 FAIL IAM policy should not apply directly to users. Should be on group", - "F34 FAIL RDS DB Cluster master user password must be Ref to NoEcho Parameter. Default credentials are not recommended", - "F26 FAIL RDS DBCluster should have StorageEncrypted enabled", - "F27 FAIL RDS DBInstance should have StorageEncrypted enabled", - "F23 FAIL RDS instance master user password must be Ref to NoEcho Parameter. Default credentials are not recommended", - "F24 FAIL RDS instance master username must be Ref to NoEcho Parameter. Default credentials are not recommended", - "F22 FAIL RDS instance should not be publicly accessible", - "F28 FAIL Redshift Cluster should have encryption enabled", - "F35 FAIL Redshift Cluster master user password must be Ref to NoEcho Parameter. Default credentials are not recommended", - "W28 WARN Resource found with an explicit name, this disallows updates that require replacement of this resource", - "W35 WARN S3 Bucket should have access logging configured", - "W20 WARN S3 Bucket policy should not allow Allow+NotAction", - "F9 FAIL S3 Bucket policy should not allow Allow+NotPrincipal", - "F15 FAIL S3 Bucket policy should not allow * action", - "F16 FAIL S3 Bucket policy should not allow * principal", - "W31 WARN S3 Bucket likely should not have a public read acl", - "F14 FAIL S3 Bucket should not have a public read-write acl", - "W5 WARN Security Groups found with cidr open to world on egress", - "W29 WARN Security Groups found egress with port range instead of just a single port", - "W9 WARN Security Groups found with ingress cidr that is not /32", - "W2 WARN Security Groups found with cidr open to world on ingress. This should never be true on instance. Permissible on ELB", - "W27 WARN Security Groups found ingress with port range instead of just a single port", - "F1000 FAIL Missing egress rule means all traffic is allowed outbound. Make this explicit if it is desired configuration", - "W19 WARN SNS Topic policy should not allow Allow+NotAction", - "F8 FAIL SNS Topic policy should not allow Allow+NotPrincipal", - "F18 FAIL SNS topic policy should not allow * principal", - "W18 WARN SQS Queue policy should not allow Allow+NotAction", - "F7 FAIL SQS Queue policy should not allow Allow+NotPrincipal", - "F20 FAIL SQS Queue policy should not allow * action", - "F21 FAIL SQS Queue policy should not allow * principal", - "F10 FAIL IAM user should not have any inline policies. Should be centralized Policy object on group", - "F2000 FAIL User is not assigned to a group", - "F665 FAIL WebAcl DefaultAction should not be ALLOW", - "F29 FAIL Workspace should have encryption enabled" - ] -} -``` +The API exposed by the Docker endpoint is cfn_nag/v1/* ### Verifying Signatures @@ -227,48 +110,26 @@ eyJmYWlsdXJlX2NvdW50IjoxLCJ2aW9sYXRpb25zIjpbeyJpZCI6IlczNSIsInR5cGUiOiJXQVJOIiwi Signature is valid! ``` -### Local Development - -#### Build dependencies -``` -sam build -``` - -#### Test Lambda +### Deployment -##### Local invoke +To deploy the Lambda, run `scripts/deploy_sam.sh` and consult the outputs for the endpoints -``` -sam local invoke -e event-json.json -sam local invoke -e event-yaml.json -``` +To deploy the Docker container locally: -##### Local API testing +docker build . +docker run -p 4567:4567 -e 'private_key_override=' -e use_https=self -``` -sam local start-api -file=~/git/cfn_nag/spec/test_templates/json/elasticsearch/elasticsearch_domain_without_explicit_name.json -curl -d "{\"template_body\": \"`base64 $file`\"}" -H "Content-Type: application/json" -X POST http://127.0.0.1:3000/scan -``` +Then hit https://localhost:4567/cfn_nag/v1/status -### Deployment +### HTTPS +The docker image observes env var use_https to determine whether to enable SSL. -These are typically one time tasks: - -``` -./scripts/create_signing_keys -./scripts/extract_libsodium.sh -``` - -For each deployment: - -``` -sam build --use-container -sam package --template-file .aws-sam/build/template.yaml --s3-bucket stelligent-cfn-nag-service --output-template-file packaged-template.yaml -sam deploy --stack-name cfn-nag-service --template-file packaged-template.yaml --capabilities CAPABILITY_IAM -``` +none means http +self means https with a self-signed cert generated by the web container +cert means a certificate of your own choosing that you must generate and map it. for example: +-e use_https=cert -e cert_public_path=/certs/cert.pem -e cert_private_path=/certs/key.pem -v ~/certs:/certs -#### Testing +#### Testing - Under development ``` file=~/git/cfn_nag/spec/test_templates/json/elasticsearch/elasticsearch_domain_with_explicit_name.json