Skip to content

Commit

Permalink
feat!: configure cloudfront with origin access control (proposal) (#376)
Browse files Browse the repository at this point in the history
### Issue

No relevant github issue but in MCP, setting a default root object is
required which this work helps to address.

### What?

- enable logging (this was added in [another merged
PR](#375))
- configure cloudfront to use origin access control and delete the
origin access identity that gets created
- set default root object to `index.html`
- use flag to enable/disable feature`VEDA_CLOUDFRONT_OAC`
### Why?

- currently, our MCP deployments need to be manually updated in order
for the cloudfront distribution to work properly with S3 buckets that
block public access

### Testing?

- deployed these changes to UAH dev and MCP test

### Other
- I opted to not add policy configuration in this PR since there is no
way to tell via CDK if a policy on a bucket already exists. In order for
this to work, the S3 browser bucket must allow cloudfront to `GetObject`
```
{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::BUCKET/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::ACCOUNT:distribution/DISTRIBUTION_ID"
                }
            }
        }
    ]
```

### Misc
In order to properly configure this for our UAH stacks, we will need to
update the buckets to block public access, not use static website
hosting, and to include the bucket policy like above. These changes are
required because our current UAH buckets do use static website hosting
and therefore don't have the above policy and allow read access.
  • Loading branch information
botanical authored Jun 14, 2024
2 parents 8863d92 + f4b89c7 commit 3a20ef2
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 17 deletions.
1 change: 1 addition & 0 deletions .example.env
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ STAC_BROWSER_BUCKET=
STAC_URL=
CERT_ARN=
VEDA_CLOUDFRONT=
VEDA_CLOUDFRONT_OAC=[OPTIONAL, CONFIGURES ORIGIN ACCESS CONTROL, DEFAULTS TO TRUE]
VEDA_CUSTOM_HOST=
5 changes: 5 additions & 0 deletions routes/infrastructure/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ class vedaRouteSettings(BaseSettings):
description="Boolean if Cloudfront Distribution should be deployed",
)

cloudfront_oac: Optional[bool] = Field(
True,
description="Boolean that configures Cloufront STAC Browser Origin with Origin Access Control",
)

# STAC S3 browser bucket name
stac_browser_bucket: Optional[str] = Field(
None, description="STAC browser S3 bucket name"
Expand Down
91 changes: 74 additions & 17 deletions routes/infrastructure/construct.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,24 +42,81 @@ def __init__(
else None
)

self.distribution = cf.Distribution(
self,
stack_name,
comment=stack_name,
default_behavior=cf.BehaviorOptions(
origin=origins.HttpOrigin(
origin_bucket.bucket_website_domain_name,
protocol_policy=cf.OriginProtocolPolicy.HTTP_ONLY,
origin_id="stac-browser",
if veda_route_settings.cloudfront_oac:
# create the origin access control resource
cfn_origin_access_control = cf.CfnOriginAccessControl(
self,
"VedaCfnOriginAccessControl",
origin_access_control_config=cf.CfnOriginAccessControl.OriginAccessControlConfigProperty(
name=f"veda-{stage}-oac",
origin_access_control_origin_type="s3",
signing_behavior="always",
signing_protocol="sigv4",
description="Origin Access Control for STAC Browser",
),
cache_policy=cf.CachePolicy.CACHING_DISABLED,
),
certificate=domain_cert,
enable_logging=True,
domain_names=[f"{stage}.{veda_route_settings.domain_hosted_zone_name}"]
if veda_route_settings.domain_hosted_zone_name
else None,
)
)

self.distribution = cf.Distribution(
self,
stack_name,
comment=stack_name,
default_behavior=cf.BehaviorOptions(
origin=origins.S3Origin(
origin_bucket, origin_id="stac-browser"
),
cache_policy=cf.CachePolicy.CACHING_DISABLED,
origin_request_policy=cf.OriginRequestPolicy.CORS_S3_ORIGIN,
response_headers_policy=cf.ResponseHeadersPolicy.CORS_ALLOW_ALL_ORIGINS,
viewer_protocol_policy=cf.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
),
certificate=domain_cert,
default_root_object="index.html",
enable_logging=True,
domain_names=[
f"{stage}.{veda_route_settings.domain_hosted_zone_name}"
]
if veda_route_settings.domain_hosted_zone_name
else None,
)
# associate the created OAC with the distribution
distribution_props = self.distribution.node.default_child
if distribution_props is not None:
distribution_props.add_override(
"Properties.DistributionConfig.Origins.0.S3OriginConfig.OriginAccessIdentity",
"",
)
distribution_props.add_property_override(
"DistributionConfig.Origins.0.OriginAccessControlId",
cfn_origin_access_control.ref,
)

# remove the OAI reference from the distribution
all_distribution_props = self.distribution.node.find_all()
for child in all_distribution_props:
if child.node.id == "S3Origin":
child.node.try_remove_child("Resource")
else:
self.distribution = cf.Distribution(
self,
stack_name,
comment=stack_name,
default_behavior=cf.BehaviorOptions(
origin=origins.HttpOrigin(
origin_bucket.bucket_website_domain_name,
protocol_policy=cf.OriginProtocolPolicy.HTTP_ONLY,
origin_id="stac-browser",
),
cache_policy=cf.CachePolicy.CACHING_DISABLED,
),
certificate=domain_cert,
default_root_object="index.html",
enable_logging=True,
domain_names=[
f"{stage}.{veda_route_settings.domain_hosted_zone_name}"
]
if veda_route_settings.domain_hosted_zone_name
else None,
)

self.distribution.add_behavior(
path_pattern="/api/stac*",
Expand Down

0 comments on commit 3a20ef2

Please sign in to comment.