How to create a KMS encrypted S3 bucket and how to access it from another account(because I always seem to mess up one step).

I’m going to preface this post by saying that everything I’m describing here should be automated via either terraform or cloud formation templates.

The flow will be to create a KMS key, then create an S3 bucket with that KMS key, then create a user in another account that can put, get and delete from that KMS bucket.

 KMS key creation

Login to the AWS console then go to the IAM service.

Click on Encryption keys on the left side of the page.

 Click on Create key and enter the alias and the description and make sure the KMS radio button is selected as the Key Material Origin under the Advanced Options.  Click Next Step.

 Enter all the required Tags and click Next Step.

 Choose the IAM users or roles that can administer the key and click Next Step.

 Choose the IAM users or roles that can use the key and click Next Step. We’ll come back to this later on.

 Click Finish and make a note of the ARN(something like arn:aws:kms:us-east-1:1234567890:key/12345678-9012-3456-7890-123456789012 )

 S3 bucket creation

 First off login to the AWS console then go to the S3 service.

 Click Create bucket and enter the Bucket name and click Next.

 Click on Default encryption.  Click on AWS-KMS and select your ARN(or alias) and click Save.

 Click Next.

 Adjust any permissions and click Next.

 Click Create bucket.

 Test some s3 operations with a user in the bucket’s account

 At this point you should be able to do the following as a user on this account:

aws s3 ls s3://test-bucket-1234

aws s3 cp test.txt s3://test-bucket-1234/test.txt

If you look at the object in the S3 console, you should notice that the Encryption property on the object is set to AWS-KMS.

 Create a user in another account with s3 access

 Login to another AWS accounts console then go to the IAM service.

 Click on Users on the left side of the page.

 Click Add user and enter a User name(i.e. srv_test_kms) and check the Programmatic access check box and click Next Permissions.

 Click Next: Review(we will add an inline policy in another step).

 Click Create user.  Make a note of the Access key ID and the Secret access key

Applying the user policy to give user access to bucket

 Apply a policy similar to the following to the user just created to limit access to the bucket in the other account:

 {

   "Version": “2012-10-17”,

   "Statement": [

       {

           "Sid": “VisualEditor0”,

           "Effect": “Allow”,

           "Action": [

               "kms:Encrypt",

               "kms:Decrypt",

               "kms:ReEncrypt*“,

              "kms:GenerateDataKey*”,

               "kms:DescribeKey"

           ],

           "Resource": “arn:aws:kms:us-east-1:1234567890:key/12345678-9012-3456-7890-123456789012”

       },

       {

           "Sid": “VisualEditor1”,

           "Effect": “Allow”,

           "Action": [

               "s3:ListBucket",

              “s3:GetBucketLocation”,

               "s3:GetObject",

               "s3:GetObjectAcl",

               "s3:PutObject",

               "s3:PutObjectAcl"

           ],

           "Resource": [

              “arn:aws:s3:::test-bucket-1234”,

              “arn:aws:s3:::test-bucket-1234/*”

           ]

       }

   ]

}

Providing the user with access to the KMS encryption key on the other account

 Login to the account with the S3 bucket / KMS key and go to the IAM service.

 Click on Encryption keys and select the key that you created earlier.

 Click over to the right of the screen where it says “Switch to policy view”.

 The policy will initially look something like this:

 {

 "Version": “2012-10-17”,

 "Id": “key-consolepolicy-3”,

 "Statement": [

   {

     "Sid": “Enable IAM User Permissions”,

     "Effect": “Allow”,

     "Principal": {

       "AWS": “arn:aws:iam::1234567890:root”

     },

     "Action": “kms:*”,

     "Resource": “*”

   }

 ]

}

You will need to modify this policy to add your users ARN from the other account.  When completed it will look something like this:

 {

 "Version": “2012-10-17”,

 "Id": “key-consolepolicy-3”,

 "Statement": [

   {

     "Sid": “Enable IAM User Permissions”,

     "Effect": “Allow”,

     "Principal": {

       "AWS": [

        “arn:aws:iam::1234567890:root”,

        “arn:aws:iam::0123456789:user/srv_test_kms”

       ]

     },

     "Action": “kms:*”,

     "Resource": “*”

   }

 ]

}

Click Save Changes.

Providing the user with access to the S3 bucket on the other account

 Login to the account with the S3 bucket / KMS key and go to the S3 service.

 Click on the S3 bucket you created earlier.

 Click on the Permissions tab for the bucket.

 Click on the Bucket Policy and add a policy similar to the following to the bucket:

 {

   "Version": “2012-10-17”,

   "Statement": [

       {

           "Sid": “Example permissions”,

           "Effect": “Allow”,

           "Principal": {

               "AWS": “arn:aws:iam::0123456789:user/srv_test_kms”

           },

           "Action": [

               "s3:ListBucket",

              “s3:GetBucketLocation”,

               "s3:GetObject",

               "s3:GetObjectAcl",

               "s3:PutObject",

               "s3:PutObjectAcl"

           ],

           "Resource": [

              “arn:aws:s3:::test-bucket-1234”,

              “arn:aws:s3:::test-bucket-1234/*”

           ]

       }

   ]

}

 Testing puts, gets, and deletes with the user on the account that does not contain the S3 bucket

 Using the access key / secret key for that user you should be able to do the following commands.

 aws s3 ls s3://test-bucket-1234

The following command will appear to work but you’ll notice an issue when you go look at the file in the S3 file explorer.  The encryption and tags properties will have “Access Denied”.  What happened here is that the acl’s are for the user uploading the file and not the bucket owner.

 aws s3 cp test.txt s3://test-bucket-1234/test.txt

To fix this issue, copy the file using the following:

aws s3 cp test.txt s3://test-bucket-1234/test.txt –acl “bucket-owner-full-control”

aws s3 cp s3://test-bucket-1234/test.txt test.txt

If you do the following, you should get an access denied error because the user does not have the DeleteObject action in the bucket policy above:

aws s3 rm s3://test-bucket-1234/test.txt