Skip to content

Add SotoSignerCloudFront module for signed URLs and cookies#696

Merged
adam-fowler merged 11 commits into
soto-project:mainfrom
sebsto:feature/cloudfront-signing
Jun 12, 2026
Merged

Add SotoSignerCloudFront module for signed URLs and cookies#696
adam-fowler merged 11 commits into
soto-project:mainfrom
sebsto:feature/cloudfront-signing

Conversation

@sebsto

@sebsto sebsto commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Adds a new SotoSignerCloudFront module that generates CloudFront signed URLs and signed cookies using RSA PKCS#1 v1.5 signatures. This is a first-class implementation of the signing logic described in the CloudFront developer guide.

Closes #613

What's included

  • New module: SotoSignerCloudFront (separate from SotoSignerV4 — uses _CryptoExtras for RSA)
  • Canned policy: signed URLs and cookies with expiration
  • Custom policy: wildcard resources, IP restrictions, optional start times
  • SHA-1 and SHA-256: both hash algorithms supported (Hash-Algorithm param appended for SHA-256)
  • Sendable: safe across concurrency domains, Swift 6 strict concurrency clean
  • Cross-platform: macOS + Linux, verified on swift:amazonlinux2023

API

let signer = try CloudFrontSigner(keyPairId: "K2JCJMDEHXQW5F", privateKey: pemString)

// Canned policy
let url = try signer.signedURL(url: "https://d111.cloudfront.net/video.mp4", expires: .hours(1))

// Custom policy with wildcard + IP restriction
let policy = CloudFrontSigner.CustomPolicy(
    resource: "https://d111.cloudfront.net/premium/*",
    expires: .hours(24),
    ipAddress: "192.0.2.0/24"
)
let url = try signer.signedURL(url: "https://d111.cloudfront.net/premium/movie.mp4", policy: policy)

// Signed cookies
let cookies = try signer.signedCookies(url: "https://d111.cloudfront.net/file.mp4", expires: .hours(2))

Testing

  • 33 unit tests covering all public API methods, edge cases, and error conditions
  • Verified on macOS (local) and Linux (docker run swift:amazonlinux2023)
  • End-to-end tested against a real CloudFront distribution — all 5 scenarios pass (canned SHA-1, canned SHA-256, custom wildcard, signed cookies, expired URL rejection)

Documentation

Includes Swift DocC documentation:

  • Module overview with usage examples
  • API reference for CloudFrontSigner
  • End-to-end testing guide (SotoCore.docc/SotoSignerCloudFront/Articles/EndToEndTesting.md) with copy-pasteable AWS CLI commands to set up a test distribution, generate signed URLs, verify with curl, and clean up all resources

@sebsto sebsto requested review from 0xTim and adam-fowler as code owners June 6, 2026 18:41
@codecov

codecov Bot commented Jun 6, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.22485% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.71%. Comparing base (9c31dc2) to head (0c58040).

Files with missing lines Patch % Lines
...toSignerCloudFront/CloudFrontSigner+Internal.swift 97.29% 1 Missing ⚠️
...nerCloudFront/CloudFrontSigner+SignedCookies.swift 97.91% 1 Missing ⚠️
...oSignerCloudFront/CloudFrontSigner+SignedURL.swift 98.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #696      +/-   ##
==========================================
+ Coverage   81.26%   81.71%   +0.44%     
==========================================
  Files          93       98       +5     
  Lines        6672     6841     +169     
==========================================
+ Hits         5422     5590     +168     
- Misses       1250     1251       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread Sources/SotoSignerCloudFront/CloudFrontSigner.swift Outdated
Comment thread Sources/SotoSignerCloudFront/CloudFrontSigner.swift Outdated
Comment thread Sources/SotoSignerCloudFront/CloudFrontSigner+SignedCookies.swift Outdated
Comment thread Sources/SotoSignerCloudFront/CloudFrontSigner.swift Outdated
Comment thread Sources/SotoSignerCloudFront/CloudFrontSigner+Internal.swift
Comment thread Sources/SotoSignerCloudFront/CloudFrontSigner+SignedURL.swift Outdated
Comment thread Sources/SotoSignerCloudFront/CloudFrontSignerError.swift Outdated
@sebsto sebsto force-pushed the feature/cloudfront-signing branch from 33cec23 to 1369d18 Compare June 11, 2026 18:36
sebsto added 8 commits June 11, 2026 20:39
Implements CloudFront RSA-based signing (PKCS#1 v1.5) as a new dedicated module,
separate from SotoSignerV4. Supports canned and custom policies for both signed
URLs and signed cookies, with SHA-1 (default) and SHA-256 hash algorithms.

New module: SotoSignerCloudFront
- CloudFrontSigner struct with Sendable conformance
- Canned policy signed URLs and cookies
- Custom policy with wildcard resources, IP restrictions, start times
- CloudFront-specific base64 encoding
- Dual PEM initializers (String + Data)
- Comprehensive error handling

Tests: 33 unit tests covering all public API methods, edge cases, error
conditions, and round-trip signature verification. Verified on both macOS
and Linux (swift:amazonlinux2023).

Documentation: Swift DocC documentation with usage examples and a complete
end-to-end testing guide (SotoCore.docc/SotoSignerCloudFront/Articles/
EndToEndTesting.md) that walks through setting up a real CloudFront
distribution and verifying signed URLs against it.

Resolves: soto-project#613
…DER encoding

- Rename privateKey: to privateKeyPEM: in the String initializer
- Replace PEM-as-Data initializer with privateKeyDER: accepting DER-encoded keys
- Update tests, docc documentation, and EndToEndTesting article
Returns an array of Set-Cookie header strings ready for use in HTTP responses,
addressing review feedback to simplify cookie usage for callers.
CloudFront uses a non-standard mapping (/ → ~, = → _) that differs from
RFC 4648 base64url, so the Swift 6.3 .base64URLAlphabet option is not applicable.
Combine separate canned/custom overloads into single methods that accept
a Policy enum (.canned(expires:) or .custom(CustomPolicy)), as suggested
in code review.
Uses a private enum code with static properties for better ABI stability
and future extensibility without breaking API changes.
@sebsto sebsto force-pushed the feature/cloudfront-signing branch from e28941d to e271765 Compare June 11, 2026 18:41

@adam-fowler adam-fowler left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of minor changes, but otherwise we are good

Comment thread Sources/SotoSignerCloudFront/CloudFrontSigner.swift Outdated
Comment thread Sources/SotoSignerCloudFront/CloudFrontSigner+Internal.swift
Comment thread Sources/SotoSignerCloudFront/CloudFrontSigner.swift Outdated
@sebsto

sebsto commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

All good.

@adam-fowler adam-fowler merged commit 47454bf into soto-project:main Jun 12, 2026
11 of 12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CloudFront signed URLs and cookies

2 participants