aws-cloudformation / cloudformation-coverage-roadmap

The AWS CloudFormation Public Coverage Roadmap
https://aws.amazon.com/cloudformation/
Creative Commons Attribution Share Alike 4.0 International
1.11k stars 54 forks source link

AWS::ElasticLoadBalancingV2::LoadBalancer - Load Balancer creation silently ignores invalid access log prefix error and creates resource with incorrect configuration #1928

Open ospatil opened 7 months ago

ospatil commented 7 months ago

Name of the resource

AWS::ElasticLoadBalancingV2::LoadBalancer

Resource Name

No response

Issue Description

When a Network Load Balancer (or ALB) is created with invalid prefix for access logging (for example - starting or ending with /) as shown in the snippet below:

nlbC39469D4:
  Type: AWS::ElasticLoadBalancingV2::LoadBalancer
  Properties:
    LoadBalancerAttributes:
      - Key: deletion_protection.enabled
        Value: "false"
      - Key: load_balancing.cross_zone.enabled
        Value: "true"
      - Key: access_logs.s3.enabled
        Value: "true"
      - Key: access_logs.s3.bucket
        Value:
          Ref: accesslogbucketBBD437A5
      - Key: access_logs.s3.prefix
        Value: /aws/nlb/accesslogs

the stack creation silently ignores the error, completes successfully and creates a load balancer without enabling the attributes the user wants enabled. In above case, the Cross-zone load balancing and Access logs remain off.

cloudformation-nlb-accesslogs-silent-fail

Expected Behavior

The stack creation should fail during the load balancer resource creation with proper error message returned to the user as feedback.

Observed Behavior

The resource creation for the load balancer and stack creation completes successfully but with incorrect and unexpected configuration.

Test Cases

  1. Crate a S3 bucket.
  2. Create a Network Load Balancer to use the above bucket in the load balancer attributes for access logging but with a prefix starting with '/' as shown in the snippet below.
    LoadBalancerAttributes:
      - Key: access_logs.s3.enabled
        Value: "true"
      - Key: access_logs.s3.bucket
        Value:
          Ref: accesslogbucketBBD437A5
      - Key: access_logs.s3.prefix
        Value: /aws/nlb/accesslogs
  3. The resource and stack creation succeeds but it should fail with descriptive error message like the following:
    The value of 'access_logs.s3.prefix' cannot start or end with '/'

CloudFormation Template to Reproduce and Test

  1. The following template can be used to see the issue in action. Save the following file as template.yaml.

    template.yaml ```js Parameters: subnetIds: Type: CommaDelimitedList Resources: accesslogbucketBBD437A5: Type: AWS::S3::Bucket Properties: BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true Tags: - Key: aws-cdk:auto-delete-objects Value: "true" VersioningConfiguration: Status: Enabled UpdateReplacePolicy: Delete DeletionPolicy: Delete Metadata: aws:cdk:path: CfLbAccesslogPrefixIssueStack/access-log-bucket/Resource accesslogbucketPolicy5393C10B: Type: AWS::S3::BucketPolicy Properties: Bucket: Ref: accesslogbucketBBD437A5 PolicyDocument: Statement: - Action: s3:* Condition: Bool: aws:SecureTransport: "false" Effect: Deny Principal: AWS: "*" Resource: - Fn::GetAtt: - accesslogbucketBBD437A5 - Arn - Fn::Join: - "" - - Fn::GetAtt: - accesslogbucketBBD437A5 - Arn - /* - Action: - s3:DeleteObject* - s3:GetBucket* - s3:List* - s3:PutBucketPolicy Effect: Allow Principal: AWS: Fn::GetAtt: - CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092 - Arn Resource: - Fn::GetAtt: - accesslogbucketBBD437A5 - Arn - Fn::Join: - "" - - Fn::GetAtt: - accesslogbucketBBD437A5 - Arn - /* - Action: s3:PutObject Effect: Allow Principal: AWS: arn:aws:iam::985666609251:root Resource: Fn::Join: - "" - - Fn::GetAtt: - accesslogbucketBBD437A5 - Arn - //aws/nlb/accesslogs/AWSLogs/782729317156/* - Action: s3:PutObject Condition: StringEquals: s3:x-amz-acl: bucket-owner-full-control Effect: Allow Principal: Service: delivery.logs.amazonaws.com Resource: Fn::Join: - "" - - Fn::GetAtt: - accesslogbucketBBD437A5 - Arn - //aws/nlb/accesslogs/AWSLogs/782729317156/* - Action: s3:GetBucketAcl Effect: Allow Principal: Service: delivery.logs.amazonaws.com Resource: Fn::GetAtt: - accesslogbucketBBD437A5 - Arn Version: "2012-10-17" Metadata: aws:cdk:path: CfLbAccesslogPrefixIssueStack/access-log-bucket/Policy/Resource accesslogbucketAutoDeleteObjectsCustomResource34EB6379: Type: Custom::S3AutoDeleteObjects Properties: ServiceToken: Fn::GetAtt: - CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F - Arn BucketName: Ref: accesslogbucketBBD437A5 DependsOn: - accesslogbucketPolicy5393C10B UpdateReplacePolicy: Delete DeletionPolicy: Delete Metadata: aws:cdk:path: CfLbAccesslogPrefixIssueStack/access-log-bucket/AutoDeleteObjectsCustomResource/Default CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Action: sts:AssumeRole Effect: Allow Principal: Service: lambda.amazonaws.com ManagedPolicyArns: - Fn::Sub: arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Metadata: aws:cdk:path: CfLbAccesslogPrefixIssueStack/Custom::S3AutoDeleteObjectsCustomResourceProvider/Role CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F: Type: AWS::Lambda::Function Properties: Code: S3Bucket: cdk-hnb659fds-assets-782729317156-ca-central-1 S3Key: b7f33614a69548d6bafe224d751a7ef238cde19097415e553fe8b63a4c8fd8a6.zip Timeout: 900 MemorySize: 128 Handler: index.handler Role: Fn::GetAtt: - CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092 - Arn Runtime: nodejs18.x Description: Fn::Join: - "" - - "Lambda function for auto-deleting objects in " - Ref: accesslogbucketBBD437A5 - " S3 bucket." DependsOn: - CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092 Metadata: aws:cdk:path: CfLbAccesslogPrefixIssueStack/Custom::S3AutoDeleteObjectsCustomResourceProvider/Handler aws:asset:path: asset.b7f33614a69548d6bafe224d751a7ef238cde19097415e553fe8b63a4c8fd8a6 aws:asset:property: Code nlbC39469D4: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: LoadBalancerAttributes: - Key: deletion_protection.enabled Value: "false" - Key: load_balancing.cross_zone.enabled Value: "true" - Key: access_logs.s3.enabled Value: "true" - Key: access_logs.s3.bucket Value: Ref: accesslogbucketBBD437A5 - Key: access_logs.s3.prefix Value: /aws/nlb/accesslogs Name: nlb-access-log-prefix-issue Scheme: internet-facing Subnets: !Ref subnetIds Type: network DependsOn: - accesslogbucketPolicy5393C10B Metadata: aws:cdk:path: CfLbAccesslogPrefixIssueStack/nlb/Resource ```
  2. Get ids of two (or more) public subnets of the default VPC in the account from different availability zones and replace <COMMA_SEPARATED_SUBNET_ID_STRING> below with the value.

  3. Create the stack using the following command: aws cloudformation create-stack --stack-name lb-accesslogs-prefix-issue --template-body file://template.yaml --parameters 'ParameterKey=subnetIds,ParameterValue="<COMMA_SEPARATED_SUBNET_ID_STRING>"' --capabilities CAPABILITY_NAMED_IAM

Other Details

Since the resource and stack creation succeeded but without enabling the attributes I wanted, I created a custom resource that used ELBv2 modifyLoadBalancerAttributes action to modify the required attributes. It gave me the correct behaviour of failing creation with the following error message:

Received response status [FAILED] from custom resource. Message returned: The value of 'access_logs.s3.prefix' cannot start or end with '/'

This is the correct behaviour and should be the expected behaviour of the load balancer resource creation too.