{"id":21470218,"url":"https://github.com/jimweller/lab-s3-presigned","last_synced_at":"2026-01-04T04:34:55.066Z","repository":{"id":273891191,"uuid":"891000049","full_name":"jimweller/lab-s3-presigned","owner":"jimweller","description":"Created by gh-repo-create.sh jimweller lab-s3-presigned public  (Tue Nov 19 14:54:24 UTC 2024)","archived":false,"fork":false,"pushed_at":"2024-11-19T14:54:27.000Z","size":288,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-23T16:12:27.728Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"HCL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jimweller.png","metadata":{},"created_at":"2024-11-19T14:54:25.000Z","updated_at":"2024-11-19T14:54:37.000Z","dependencies_parsed_at":null,"dependency_job_id":"e04fb312-8352-4fca-9aa2-02b74580496a","html_url":"https://github.com/jimweller/lab-s3-presigned","commit_stats":null,"previous_names":["jimweller/lab-s3-presigned"],"tags_count":null,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jimweller%2Flab-s3-presigned","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jimweller%2Flab-s3-presigned/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jimweller%2Flab-s3-presigned/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jimweller%2Flab-s3-presigned/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jimweller","download_url":"https://codeload.github.com/jimweller/lab-s3-presigned/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243988956,"owners_count":20379649,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["lab"],"created_at":"2024-11-23T09:25:02.652Z","updated_at":"2026-01-04T04:34:55.020Z","avatar_url":"https://github.com/jimweller.png","language":"HCL","funding_links":[],"categories":[],"sub_categories":[],"readme":"# AWS S3 and CloudFront Presigned URL Demo\n\nThis demo creates a simple architecture that represents a potential flow of\npackage downloads. There are two \"channels.\" The API channel to generate time\nboxed, secure, presigned download URLs. And the data channel for downloading\npackages from an S3 bucket.\n\n## Architecture\n\n![architecture diagram](diagram.drawio.svg)\n\nThere are two solution options, S3 presigned and CloudFront presigned.\n\nPackages are stored on an S3 bucket.\n\nThe S3 is NOT publicly available. Access is only available through presigned keys.\n\nBoth methods are the same use case and pattern with different technical implementations. The pattern is:\n\n1. The actor (user or agent) makes an API call to request an presigned, time boxed URL to use for downloading a package\n2. The actor uses the resulting URL to securely download a package before the timeout expires\n\nThe S3 method (`/presign-s3-url`)calls a lambda that uses the S3 APIs to\ngenerate the URL. This is native to S3. Hostnames will vary by region or S3\nbucket.\n\nThe CloudFront method (`/presign-custom-url`)  calls a lambda that uses an RSA\nkey trusted by the CloudFront distribution. The key is used to generate the\nURL. The key is kept in Secret Manager. The Key ID is kept in SSM Parameter\nStore. This pattern allows for a single ExampleCo host name. This is effectively a\nfacade on S3.\n\nTraffic is enrypted. Both methods use HTTPS with TLS with certificates with\ntrusted chains. S3 uses native AWS urls and certificates. CloudFront uses an AWS\nCertificate Manager (ACM) certificate. ACM automatically generates and rotates\nthe certificate.\n\nStorage is encrypted. The S3 bucket has encryption enabled.\n\n## Usage\n\nAssume aws credentials on the console. Run test.sh or test.ps1 (assuming the\nterraform is applied).\n\n![test harness screenshot](screenshot.png)\n\n## Notes\n\n- S3 Presigned URLs\n  - Multiple domain names for customers to allow-list\n  - AWS domain names\n  - global geography is more difficult\n  - simple to generate\n  - less expensive\n\n- CloudFront Presigned URLs\n  - Single domain name for customers to allow-list\n  - ExampleCo domain name\n  - global geography is built in (caching, proximity, etc.)\n  - more steps to generate\n  - more expensive\n\nThere is another solution option, [hosting a private S3 VPC endpoint in a\nVPC](https://aws.amazon.com/blogs/networking-and-content-delivery/hosting-internal-https-static-websites-with-alb-s3-and-privatelink/)\nand fronting it with a load balancer. I consider this less cloud native (more\nbrittle, less features, harder to scale, more complex, etc.).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjimweller%2Flab-s3-presigned","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjimweller%2Flab-s3-presigned","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjimweller%2Flab-s3-presigned/lists"}