S3 bucket with hash postfix

Reference:

The purpose of this laboratory is to create a S3 bucket with a random hash suffix, this hash need to be computed at the creation moment and for further updates it will be preserve.

I tried to put the suffix with a simple hash, but immediately we can notice that the suffix change every time.

class S3BucketStack(core.Stack):
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        #create an S3 bucket
        hash = uuid.uuid4().hex[:6]
        bucket_name = self.node.try_get_context("bucket_name")
        s3Bucket = s3.Bucket(self, 'Bucket', bucket_name=f'{bucket_name}-{hash}')
        core.Tag.add(s3Bucket, "key", "value")
 (master **)$ cdk --profile hgmiguel.mx diff
Stack cdk-labs
Resources
[~] AWS::S3::Bucket Bucket Bucket83908E77 replace
 └─ [~] BucketName (requires replacement)
     ├─ [-] hgmiguel.mx.test
     └─ [+] hgmiguel.mx.test-1a04f6

In the next execution the hash value change again.

 (master **)$ cdk --profile hgmiguel.mx diff
Stack cdk-labs
Resources
[~] AWS::S3::Bucket Bucket Bucket83908E77 replace
 └─ [~] BucketName (requires replacement)
     ├─ [-] hgmiguel.mx.test
     └─ [+] hgmiguel.mx.test-ba38c8

I tried to archive this only with CDK but I didn’t make it. It was so difficult to create the parameter store at the beginning that I abandoned quickly.

I had thought about integrate sdk with boto3, and that made it.

    def get_hash(self, bucket_name):
        client = boto3.client('ssm')
        s3_hash_parameter = self.node.try_get_context("s3_hash_parameter")
        try:
            response = client.get_parameter(
                Name=s3_hash_parameter,
                WithDecryption=True
            )

            s3_hashes = json.loads(response['Parameter']['Value'])
            if bucket_name in s3_hashes:
                return s3_hashes[bucket_name]
            else:
                s3_hashes[bucket_name] = uuid.uuid4().hex[:6]
        except  Exception as e:
            print(e)
            s3_hashes = {bucket_name: uuid.uuid4().hex[:6]}

        response = client.put_parameter(
            Name=s3_hash_parameter,
            Value=json.dumps(s3_hashes),
            Type='SecureString',
            Overwrite=True,
            Tier='Intelligent-Tiering'
        )

        return s3_hashes[bucket_name]

At the moment of synth we can observe that the parameter store was created also the hash value was saved.

(master **)$ cdk --profile hgmiguel.mx synth
An error occurred (ParameterNotFound) when calling the GetParameter operation:
c6e230
Resources:
  Bucket83908E77:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: hgmiguel.mx.test-c6e230
      Tags:
        - Key: key
          Value: value
    UpdateReplacePolicy: Retain
    DeletionPolicy: Retain
    Metadata:

Parameter Store

If we execute the synt again, we can notice that the hash is preserved

 (master **)$ cdk --profile hgmiguel.mx synth
c6e230
Resources:
  Bucket83908E77:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: hgmiguel.mx.test-c6e230
      Tags:
        - Key: key
          Value: value

Now we can procced to do the deploy

 (master **)$ cdk deploy --profile hgmiguel.mx
c6e230
cdk-labs: deploying...
cdk-labs: creating CloudFormation changeset...
 0/3 | 1:11:07 PM | CREATE_IN_PROGRESS   | AWS::CDK::Metadata | CDKMetadata
 0/3 | 1:11:07 PM | CREATE_IN_PROGRESS   | AWS::S3::Bucket    | Bucket (Bucket83908E77)
 0/3 | 1:11:08 PM | CREATE_IN_PROGRESS   | AWS::S3::Bucket    | Bucket (Bucket83908E77) Resource creation Initiated
 0/3 | 1:11:09 PM | CREATE_IN_PROGRESS   | AWS::CDK::Metadata | CDKMetadata Resource creation Initiated
 1/3 | 1:11:09 PM | CREATE_COMPLETE      | AWS::CDK::Metadata | CDKMetadata
 2/3 | 1:11:29 PM | CREATE_COMPLETE      | AWS::S3::Bucket    | Bucket (Bucket83908E77)
 3/3 | 1:11:31 PM | CREATE_COMPLETE      | AWS::CloudFormation::Stack | cdk-labs

 ✅  cdk-labs    

S3 bucket

If we made a change like eneable encryptation, if we made a diff we can notice that cdk use the same hash.

 (master **)$ cdk diff --profile hgmiguel.mx
c6e230
Stack cdk-labs
IAM Statement Changes

.....
(Changes happen here)
....

(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Resources
[+] AWS::KMS::Key Bucket/Key BucketKey7E4AEAB8
[~] AWS::S3::Bucket Bucket Bucket83908E77
 └─ [+] BucketEncryption
     └─ {"ServerSideEncryptionConfiguration":[{"ServerSideEncryptionByDefault":{"KMSMasterKeyID":{"Fn::GetAtt":["BucketKey7E4AEAB8","Arn"]},"SSEAlgorithm":"aws:kms"}}]}

If we made the deploy, the change is applied on the same bucket

S3 encryptation

Issues

cdk destroy doesn’t work any more. 2020-03-28 14:02:01 UTC-0600 Bucket83908E77 CREATE_FAILED hgmiguel.mx.test-c6e230 already exists