Live data from Hacker News

Libaws: A simpler way to declare AWS infrastructure

github.com

91–93 of 93 posts

Re: Libaws: A simpler way to declare AWS infrastructure

#91
post #89

Earlier quoted context omitted.

In the early days, people would write imperative scripts to provision infrastructure, but once it's out there you can't just delete resources that you no longer want by deleting the relevant blocks from your script and re-running it--you had to delete them manually or write a "migration script". This was untenable. Then some tools came out which let you use YAML or JSON to describe the desired state of the world, and…

> Eventually the industry caught on to the scam and demanded programming languages back, so we got CDKs which misunderstand the assignment in a different way. Rather than emitting YAML… You’re in for a shock when you realise all they do is emit YAML

Maybe they do, but if you have to tack on a bunch of inheritance and run everything through a node process just to emit YAML then you've lost all of the benefits of "just emit YAML".

Re: Libaws: A simpler way to declare AWS infrastructure

#92

Earlier quoted context omitted.

In the early days, people would write imperative scripts to provision infrastructure, but once it's out there you can't just delete resources that you no longer want by deleting the relevant blocks from your script and re-running it--you had to delete them manually or write a "migration script". This was untenable. Then some tools came out which let you use YAML or JSON to describe the desired state of the world, and…

Amazon's CDK emits YAML. Troposphere emits YAML. You can diff the outputs if you wish, or did I misunderstand your last paragraph.

"Just emit YAML" is about avoiding all of the inheritance and javascript IPC in favor of writing straightforward YAML-builder code in the host language (more like Troposphere, but Troposphere also has poor ergonomics).

These are two examples I found online. The first is more complicated but it doesn't do any JavaScript IPC, no inheritance, no mutation, etc. You write it just like you want to write YAML, and it straightforwardly emits YAML (rather than the CDK version which is more opaque/magical). I prefer this:

    def main():
        bucket_name_parameter = ParameterString(Description="The name of the bucket")
        key_arn_parameter = ParameterString(
            Description="The ARN of the KMS key used to encrypt the bucket",
        )
        bucket = Bucket(BucketName=bucket_name_parameter)
        t = Template(
            description="S3 Bucket Template",
            parameters={
                "BucketName": bucket_name_parameter,
                "KMSKeyARN": key_arn_parameter,
            },
            resources={
                "Bucket": bucket,
                "BucketPolicy": ManagedPolicy(
                    PolicyDocument={
                        "Version": "2012-10-17",
                        "Statement": [
                            {
                                "Sid": "AllowFullAccessToBucket",
                                "Action": "s3:*",
                                "Effect": "Allow",
                                "Resource": Sub(
                                    f"${{BucketARN}}/*", BucketARN=bucket.GetArn()
                                ),
                            },
                            {
                                "Sid": "AllowUseOfTheKey",
                                "Effect": "Allow",
                                "Action": [
                                    "kms:Encrypt",
                                    "kms:Decrypt",
                                    "kms:ReEncrypt*",
                                    "kms:GenerateDataKey*",
                                    "kms:DescribeKey",
                                ],
                                "Resource": key_arn_parameter,
                            },
                            {
                                "Sid": "AllowAttachmentOfPersistentResources",
                                "Effect": "Allow",
                                "Action": [
                                    "kms:CreateGrant",
                                    "kms:ListGrants",
                                    "kms:RevokeGrant",
                                ],
                                "Resource": key_arn_parameter,
                                "Condition": {"Bool": {"kms:GrantIsForAWSResource": True}},
                            },
                        ],
                    },
                ),
            },
        )
        print(json.dumps(t.template_to_cloudformation(), indent=4))
Rather than this:

    class S3Stack(Stack):
        def __init__(self, app: App, id: str) -> None:
            super().__init__(app, id)
            self.access_point = f"arn:aws:s3:{Aws.REGION}:{Aws.ACCOUNT_ID}:accesspoint/" \
                f"{S3_ACCESS_POINT_NAME}"
    
            # Set up a bucket
            bucket = s3.Bucket(
               self,
               "example-bucket",
               access_control=s3.BucketAccessControl.BUCKET_OWNER_FULL_CONTROL,
               encryption=s3.BucketEncryption.S3_MANAGED,
               block_public_access=s3.BlockPublicAccess.BLOCK_ALL,
            )
            # Delegating access control to access points
            # https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-points-policies.html
            bucket.add_to_resource_policy(
                iam.PolicyStatement(
                    actions=["*"],
                    principals=[iam.AnyPrincipal()],
                    resources=[
                        bucket.bucket_arn,
                        bucket.arn_for_objects('*')
                    ],
                    conditions={
                        "StringEquals":
                            {
                                "s3:DataAccessPointAccount": f"{Aws.ACCOUNT_ID}"
                            }
                    }
                ),
            )
Note: Compared to Troposphere, the bindings in the first example are completely generated from a spec published by AWS, so they never fall behind. They're also type-annotated so you can use those bindings with type safety. Sadly, the project has been abandoned because it's CloudFormation-specific and the world has moved away from CloudFormation.

Re: Libaws: A simpler way to declare AWS infrastructure

#93

Earlier quoted context omitted.

In the early days, people would write imperative scripts to provision infrastructure, but once it's out there you can't just delete resources that you no longer want by deleting the relevant blocks from your script and re-running it--you had to delete them manually or write a "migration script". This was untenable. Then some tools came out which let you use YAML or JSON to describe the desired state of the world, and…

CDK outputs CloudFormation templates that you can pass to any other tool if you wish. CDK is technically just a glorified shim over CFN (although 1000x better but you do get caught in the awkwardness that is CFN many times).

It does, but very indirectly which defeats the point of "just emit YAML". I regret phrasing it that way as it seems to have caused a lot of confusion. See my responses to sibling comments for more information.
Post reply on HN