Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

S3 Server-Side Encryption #784

Merged
merged 6 commits into from
Jul 6, 2018
Merged

S3 Server-Side Encryption #784

merged 6 commits into from
Jul 6, 2018

Conversation

austinbyers
Copy link
Contributor

@austinbyers austinbyers commented Jul 6, 2018

to: @jacknagz
cc: @airbnb/streamalert-maintainers
size: medium
part of #758

Background

S3 Server-Side Encryption adds a layer of protection to data in S3 buckets. If encrypted with KMS, additional permissions to use the KMS key are required for access (in addition to access to S3).

Changes

  • Create a new KMS key for server-side encryption of most StreamAlert S3 buckets: athena results, streamalert.data, streamalert.secrets, streamalert.terraform.state, streamalerts
    • This means data in streamalert.secrets is actually encrypted twice (client-side and server-side). We will eventually move these into Secrets Manager and get rid of this S3 bucket completely
  • Create a new KMS key for each configured CloudTrail
  • The data/alerts firehoses are configured to use the KMS key corresponding to their target S3 buckets
  • After @ryandeivert upgraded moto, some of the Lambda mocking has taken longer or started throwing exceptions. For these, I just used basic mocks in place of moto.

Testing

  • Deploy from scratch from this branch with cloudtrail and a firehose enabled. Alerts landed in S3, encrypted, and were searchable from Athena. The firehose data also landed in the data bucket (encrypted).
  • Deploy from master, then apply these changes:
Terraform will perform the following actions:

  + aws_kms_alias.server_side_encryption
      id:                                                                                                        <computed>
      arn:                                                                                                       <computed>
      name:                                                                                                      "alias/encryptallthings_server-side-encryption"
      target_key_arn:                                                                                            <computed>
      target_key_id:                                                                                             "${aws_kms_key.server_side_encryption.key_id}"

  + aws_kms_key.server_side_encryption
      id:                                                                                                        <computed>
      arn:                                                                                                       <computed>
      description:                                                                                               "StreamAlert S3 Server-Side Encryption"
      enable_key_rotation:                                                                                       "true"
      is_enabled:                                                                                                "true"
      key_id:                                                                                                    <computed>
      key_usage:                                                                                                 <computed>
      policy:                                                                                                    "{\"Version\": \"2012-10-17\", \"Statement\": [{\"Action\": \"kms:*\", \"Principal\": {\"AWS\": \"arn:aws:iam::ACCOUNTID:root\"}, \"Resource\": \"*\", \"Effect\": \"Allow\", \"Sid\": \"Enable IAM User Permissions\"}, {\"Resource\": \"*\", \"Effect\": \"Allow\", \"Sid\": \"Allow principals in the account to use the key\", \"Action\": [\"kms:Decrypt\", \"kms:GenerateDataKey*\", \"kms:Encrypt\"], \"Condition\": {\"StringEquals\": {\"kms:CallerAccount\": \"ACCOUNTID\"}}, \"Principal\": \"*\"}]}"

  ~ aws_s3_bucket.logging_bucket
      server_side_encryption_configuration.#:                                                                    "0" => "1"
      server_side_encryption_configuration.0.rule.#:                                                             "0" => "1"
      server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.#:                   "0" => "1"
      server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.0.sse_algorithm:     "" => "AES256"

  ~ aws_s3_bucket.stream_alert_secrets
      server_side_encryption_configuration.#:                                                                    "0" => "1"
      server_side_encryption_configuration.0.rule.#:                                                             "0" => "1"
      server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.#:                   "0" => "1"
      server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.0.kms_master_key_id: "" => "${aws_kms_key.server_side_encryption.key_id}"
      server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.0.sse_algorithm:     "" => "aws:kms"

  ~ aws_s3_bucket.streamalerts
      server_side_encryption_configuration.#:                                                                    "0" => "1"
      server_side_encryption_configuration.0.rule.#:                                                             "0" => "1"
      server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.#:                   "0" => "1"
      server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.0.kms_master_key_id: "" => "${aws_kms_key.server_side_encryption.key_id}"
      server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.0.sse_algorithm:     "" => "aws:kms"

  ~ aws_s3_bucket.terraform_remote_state
      server_side_encryption_configuration.#:                                                                    "0" => "1"
      server_side_encryption_configuration.0.rule.#:                                                             "0" => "1"
      server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.#:                   "0" => "1"
      server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.0.kms_master_key_id: "" => "${aws_kms_key.server_side_encryption.key_id}"
      server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.0.sse_algorithm:     "" => "aws:kms"

 <= module.alert_processor_iam.data.aws_iam_policy_document.output_secrets
      id:                                                                                                        <computed>
      json:                                                                                                      <computed>
      statement.#:                                                                                               "2"
      statement.0.actions.#:                                                                                     "2"
      statement.0.actions.1493550787:                                                                            "kms:DescribeKey"
      statement.0.actions.3733000735:                                                                            "kms:Decrypt"
      statement.0.effect:                                                                                        "Allow"
      statement.0.resources.#:                                                                                   <computed>
      statement.1.actions.#:                                                                                     "1"
      statement.1.actions.2071725391:                                                                            "s3:GetObject"
      statement.1.effect:                                                                                        "Allow"
      statement.1.resources.#:                                                                                   "1"
      statement.1.resources.1019851817:                                                                          "arn:aws:s3:::encryptallthings.streamalert.secrets/*"

  ~ module.alert_processor_iam.aws_iam_role_policy.output_secrets
      policy:                                                                                                    "{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Sid\": \"\",\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"kms:DescribeKey\",\n        \"kms:Decrypt\"\n      ],\n      \"Resource\": \"arn:aws:kms:us-east-1:121671312944:key/UUID\"\n    },\n    {\n      \"Sid\": \"\",\n      \"Effect\": \"Allow\",\n      \"Action\": \"s3:GetObject\",\n      \"Resource\": \"arn:aws:s3:::encryptallthings.streamalert.secrets/*\"\n    }\n  ]\n}" => "${data.aws_iam_policy_document.output_secrets.json}"

  ~ module.cloudtrail_prod.aws_cloudtrail.streamalert_no_cloudwatch
      kms_key_id:                                                                                                "" => "${aws_kms_key.cloudtrail_encryption.arn}"

  + module.cloudtrail_prod.aws_kms_alias.cloudtrail_encryption
      id:                                                                                                        <computed>
      arn:                                                                                                       <computed>
      name:                                                                                                      "alias/encryptallthings-prod-streamalert-cloudtrail"
      target_key_arn:                                                                                            <computed>
      target_key_id:                                                                                             "${aws_kms_key.cloudtrail_encryption.key_id}"

  + module.cloudtrail_prod.aws_kms_key.cloudtrail_encryption
      id:                                                                                                        <computed>
      arn:                                                                                                       <computed>
      description:                                                                                               "Encrypt Cloudtrail logs for encryptallthings.prod.streamalert.cloudtrail"
      enable_key_rotation:                                                                                       "true"
      is_enabled:                                                                                                "true"
      key_id:                                                                                                    <computed>
      key_usage:                                                                                                 <computed>
      policy:                                                                                                    "{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Sid\": \"Enable IAM User Permissions\",\n      \"Effect\": \"Allow\",\n      \"Action\": \"kms:*\",\n      \"Resource\": \"*\",\n      \"Principal\": {\n        \"AWS\": \"arn:aws:iam::ACCOUNTID:root\"\n      }\n    },\n    {\n      \"Sid\": \"Allow CloudTrail to encrypt logs\",\n      \"Effect\": \"Allow\",\n      \"Action\": \"kms:GenerateDataKey*\",\n      \"Resource\": \"*\",\n      \"Principal\": {\n        \"Service\": \"cloudtrail.amazonaws.com\"\n      },\n      \"Condition\": {\n        \"StringLike\": {\n          \"kms:EncryptionContext:aws:cloudtrail:arn\": \"arn:aws:cloudtrail:*:ACCOUNTID:trail/*\"\n        }\n      }\n    },\n    {\n      \"Sid\": \"Allow CloudTrail to describe key\",\n      \"Effect\": \"Allow\",\n      \"Action\": \"kms:DescribeKey\",\n      \"Resource\": \"*\",\n      \"Principal\": {\n        \"Service\": \"cloudtrail.amazonaws.com\"\n      }\n    },\n    {\n      \"Sid\": \"Allow principals in the account to decrypt log files\",\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"kms:ReEncryptFrom\",\n        \"kms:Decrypt\"\n      ],\n      \"Resource\": \"*\",\n      \"Principal\": \"*\",\n      \"Condition\": {\n        \"StringEquals\": {\n          \"kms:CallerAccount\": \"ACCOUNTID\"\n        },\n        \"StringLike\": {\n          \"kms:EncryptionContext:aws:cloudtrail:arn\": \"arn:aws:cloudtrail:*:ACCOUNTID:trail/*\"\n        }\n      }\n    }\n  ]\n}"

  ~ module.cloudtrail_prod.aws_s3_bucket.cloudtrail_bucket
      server_side_encryption_configuration.#:                                                                    "0" => "1"
      server_side_encryption_configuration.0.rule.#:                                                             "0" => "1"
      server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.#:                   "0" => "1"
      server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.0.kms_master_key_id: "" => "${aws_kms_key.cloudtrail_encryption.key_id}"
      server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.0.sse_algorithm:     "" => "aws:kms"

  ~ module.kinesis_firehose_binaryalert.aws_kinesis_firehose_delivery_stream.stream_alert_data
      s3_configuration.0.kms_key_arn:                                                                            "" => "${var.kms_key_arn}"

 <= module.kinesis_firehose_setup.data.aws_iam_policy_document.firehose_s3
      id:                                                                                                        <computed>
      json:                                                                                                      <computed>
      statement.#:                                                                                               "2"
      statement.0.actions.#:                                                                                     "6"
      statement.0.actions.2071725391:                                                                            "s3:GetObject"
      statement.0.actions.315547055:                                                                             "s3:PutObject"
      statement.0.actions.329996733:                                                                             "s3:AbortMultipartUpload"
      statement.0.actions.3948445924:                                                                            "s3:GetBucketLocation"
      statement.0.actions.486976917:                                                                             "s3:ListBucket"
      statement.0.actions.548422:                                                                                "s3:ListBucketMultipartUploads"
      statement.0.effect:                                                                                        "Allow"
      statement.0.resources.#:                                                                                   "2"
      statement.0.resources.1001773326:                                                                          "arn:aws:s3:::encryptallthings.streamalert.data/*"
      statement.0.resources.1026980626:                                                                          "arn:aws:s3:::encryptallthings.streamalert.data"
      statement.1.actions.#:                                                                                     "3"
      statement.1.actions.271337083:                                                                             "kms:Encrypt"
      statement.1.actions.3733000735:                                                                            "kms:Decrypt"
      statement.1.actions.886236925:                                                                             "kms:GenerateDataKey*"
      statement.1.effect:                                                                                        "Allow"
      statement.1.resources.#:                                                                                   <computed>

  ~ module.kinesis_firehose_setup.aws_iam_role_policy.stream_alert_firehose_s3
      policy:                                                                                                    "{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Sid\": \"\",\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"s3:PutObject\",\n        \"s3:ListBucketMultipartUploads\",\n        \"s3:ListBucket\",\n        \"s3:GetObject\",\n        \"s3:GetBucketLocation\",\n        \"s3:AbortMultipartUpload\"\n      ],\n      \"Resource\": [\n        \"arn:aws:s3:::encryptallthings.streamalert.data/*\",\n        \"arn:aws:s3:::encryptallthings.streamalert.data\"\n      ]\n    }\n  ]\n}" => "${data.aws_iam_policy_document.firehose_s3.json}"

  ~ module.kinesis_firehose_setup.aws_s3_bucket.stream_alert_data
      server_side_encryption_configuration.#:                                                                    "0" => "1"
      server_side_encryption_configuration.0.rule.#:                                                             "0" => "1"
      server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.#:                   "0" => "1"
      server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.0.kms_master_key_id: "" => "${var.kms_key_id}"
      server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.0.sse_algorithm:     "" => "aws:kms"

  ~ module.stream_alert_athena.aws_s3_bucket.athena_results_bucket
      server_side_encryption_configuration.#:                                                                    "0" => "1"
      server_side_encryption_configuration.0.rule.#:                                                             "0" => "1"
      server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.#:                   "0" => "1"
      server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.0.kms_master_key_id: "" => "${var.kms_key_id}"
      server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.0.sse_algorithm:     "" => "aws:kms"

  ~ module.globals.module.alerts_firehose.aws_kinesis_firehose_delivery_stream.stream_alerts
      s3_configuration.0.kms_key_arn:                                                                            "" => "${var.kms_key_arn}"


Plan: 4 to add, 12 to change, 0 to destroy.

Athena queries worked the same (with no observable performance impact) with none, some, or all objects KMS encrypted.

@austinbyers austinbyers added this to the 2.0.0 milestone Jul 6, 2018
@austinbyers austinbyers requested a review from jacknagz July 6, 2018 21:15
@@ -1,3 +1,87 @@
// KMS key for encrypting CloudTrail logs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reference in AWS docs for the policies below? If so could you add it? 🙇

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sadly not (that I'm aware of). I got the policy by manually creating a CloudTrail, encrypting it from the console, and seeing what policy AWS automatically attached to the key. I'll add a comment to that effect


data "aws_iam_policy_document" "cloudtrail_encryption" {
statement {
sid = "Enable IAM User Permissions"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this policy to allow root to manage the key?

Copy link
Contributor Author

@austinbyers austinbyers Jul 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sort of - it's a required policy that enables any IAM user in the account (with the appropriate permissions) to manage the key - https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html#key-policy-default-allow-root-enable-iam

So if this permission is granted to "root", I as an IAM user in the account am allowed to modify the key, provided that I have kms:* permissions on my IAM user

Copy link
Contributor

@jacknagz jacknagz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two comments, LGTM otherwise!

@coveralls
Copy link

coveralls commented Jul 6, 2018

Coverage Status

Coverage remained the same at 97.385% when pulling 16924fe on austin-s3-encryption into ea5ebe3 on master.

@austinbyers austinbyers merged commit dab2658 into master Jul 6, 2018
@austinbyers austinbyers deleted the austin-s3-encryption branch July 6, 2018 21:58
@ryandeivert ryandeivert modified the milestones: 2.0.0, pro Jul 9, 2018
@ryandeivert ryandeivert modified the milestones: pro, 2.0.0 Jul 9, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants