mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2026-05-08 04:23:59 +02:00
Add the AWS deployment assets needed to run Vaultwarden serverlessly from this branch. The stack runs Vaultwarden as a Lambda function behind CloudFront, stores runtime data in S3, uses Aurora DSQL for the database, and sends mail through SES when a sender address is configured. Provide the SAM template, Cargo Lambda configuration, local and GitHub Actions build flows, deployment helper, and deployment notes. Configure the data bucket for versioning, SSE-KMS, Intelligent-Tiering, and multipart cleanup, and grant the Lambda role the S3, DSQL, and SES permissions required by the runtime. Serve the web vault from a separate S3 origin behind CloudFront and route API, identity, admin, and attachment paths to the Lambda origin. Preserve the CSP and response header policy needed for web vault assets and S3 presigned URL access.
575 lines
21 KiB
YAML
575 lines
21 KiB
YAML
AWSTemplateFormatVersion: '2010-09-09'
|
|
Description: AWS CloudFormation template for running VaultWarden on AWS serverless services.
|
|
|
|
Parameters:
|
|
Domain:
|
|
Type: String
|
|
Description: >-
|
|
The domain name for the Vaultwarden instance (e.g. https://example.com). If this parameter or the ACMCertificateArn
|
|
parameter are left empty, the Vaultwarden instance can still be reached at the output CDN domain
|
|
(e.g. https://xxxxxxxx.cloudfront.net).
|
|
AllowedPattern: (https://[a-z0-9.-]+|)
|
|
Default: ''
|
|
ACMCertificateArn:
|
|
Type: String
|
|
Description: The ARN of a us-east-1 ACM certificate to use for the domain. Required if the `Domain` parameter is set.
|
|
AllowedPattern: (arn:aws:acm:us-east-1:[0-9]+:certificate/[0-9a-f-]+|)
|
|
Default: ''
|
|
DSQLClusterId:
|
|
Type: String
|
|
Description: The endpoint of the DSQL database.
|
|
AllowedPattern: '[a-z0-9]+'
|
|
APILogRetention:
|
|
Type: Number
|
|
Description: The number of days to retain the API logs. -1 means to never expire.
|
|
Default: -1
|
|
AllowedValues: [-1, 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1096, 1827, 2192, 2557, 2922, 3288, 3653]
|
|
SignupsAllowed:
|
|
Type: String
|
|
Description: Controls if new users can register
|
|
Default: 'true'
|
|
AllowedValues: ['true', 'false']
|
|
IconService:
|
|
Type: String
|
|
Description: Allowed icon service sources.
|
|
Default: bitwarden
|
|
AdminToken:
|
|
Type: String
|
|
Description: Token for the admin interface, preferably an Argon2 PCH string. If empty, the admin interface will be disabled.
|
|
Default: ''
|
|
SMTPFrom:
|
|
Type: String
|
|
Description: The email address to send emails from. Email service is disabled if this value is empty.
|
|
Default: ''
|
|
SMTPFromName:
|
|
Type: String
|
|
Description: The name to send emails from.
|
|
Default: Vaultwarden
|
|
|
|
Mappings:
|
|
IconSource:
|
|
internal:
|
|
CSP: ''
|
|
bitwarden:
|
|
CSP: https://icons.bitwarden.net/
|
|
duckduckgo:
|
|
CSP: https://icons.duckduckgo.com/ip3/
|
|
google:
|
|
CSP: https://www.google.com/s2/favicons https://*.gstatic.com/favicon
|
|
|
|
Conditions:
|
|
IsDomainAndCertificateSet: !And
|
|
- !Not [!Equals [!Ref Domain, '']]
|
|
- !Not [!Equals [!Ref ACMCertificateArn, '']]
|
|
IsApiLogRetentionNeverExpire: !Equals
|
|
- !Ref APILogRetention
|
|
- -1
|
|
IconSourceIsPredefined: !Or
|
|
- !Equals [!Ref IconService, internal]
|
|
- !Equals [!Ref IconService, bitwarden]
|
|
- !Equals [!Ref IconService, duckduckgo]
|
|
- !Equals [!Ref IconService, google]
|
|
IsAdminTokenEmpty: !Equals
|
|
- !Ref AdminToken
|
|
- ''
|
|
IsEmailEnabled: !Not
|
|
- !Equals
|
|
- !Ref SMTPFrom
|
|
- ''
|
|
|
|
Resources:
|
|
DataBucket:
|
|
Type: AWS::S3::Bucket
|
|
Properties:
|
|
BucketEncryption:
|
|
ServerSideEncryptionConfiguration:
|
|
- BucketKeyEnabled: true
|
|
ServerSideEncryptionByDefault:
|
|
SSEAlgorithm: aws:kms
|
|
BucketName: !Sub ${AWS::StackName}-${AWS::AccountId}-${AWS::Region}-data
|
|
CorsConfiguration:
|
|
CorsRules:
|
|
- AllowedMethods:
|
|
- GET
|
|
- HEAD
|
|
AllowedOrigins:
|
|
- '*'
|
|
LifecycleConfiguration:
|
|
Rules:
|
|
- AbortIncompleteMultipartUpload:
|
|
DaysAfterInitiation: 2
|
|
ExpiredObjectDeleteMarker: true
|
|
NoncurrentVersionExpiration:
|
|
NoncurrentDays: 30
|
|
Status: Enabled
|
|
PublicAccessBlockConfiguration:
|
|
BlockPublicAcls: true
|
|
BlockPublicPolicy: true
|
|
IgnorePublicAcls: true
|
|
RestrictPublicBuckets: true
|
|
VersioningConfiguration:
|
|
Status: Enabled
|
|
|
|
DataBucketEnforceEncryptionAndStorageTier:
|
|
Type: AWS::S3::BucketPolicy
|
|
Properties:
|
|
Bucket: !Ref DataBucket
|
|
PolicyDocument:
|
|
Version: '2012-10-17'
|
|
Statement:
|
|
- Sid: DenyUnencryptedObjectUploads
|
|
Effect: Deny
|
|
Principal: '*'
|
|
Action: s3:PutObject
|
|
Resource: !Sub arn:${AWS::Partition}:s3:::${DataBucket}/*
|
|
Condition:
|
|
'Null':
|
|
s3:x-amz-server-side-encryption-aws-kms-key-id: true
|
|
- Sid: DenyUnencryptedTransit
|
|
Effect: Deny
|
|
Principal: '*'
|
|
Action: s3:*
|
|
Resource:
|
|
- !Sub arn:${AWS::Partition}:s3:::${DataBucket}
|
|
- !Sub arn:${AWS::Partition}:s3:::${DataBucket}/*
|
|
Condition:
|
|
Bool:
|
|
aws:SecureTransport: false
|
|
- Sid: DenyNonIntelligentTieringStorageClass
|
|
Effect: Deny
|
|
Principal: '*'
|
|
Action: s3:PutObject
|
|
Resource: !Sub arn:aws:s3:::${DataBucket}/*
|
|
Condition:
|
|
StringNotEquals:
|
|
s3:x-amz-storage-class: INTELLIGENT_TIERING
|
|
|
|
ApiFunctionRole:
|
|
Type: AWS::IAM::Role
|
|
Properties:
|
|
AssumeRolePolicyDocument:
|
|
Version: '2012-10-17'
|
|
Statement:
|
|
- Action: sts:AssumeRole
|
|
Effect: Allow
|
|
Principal:
|
|
Service: lambda.amazonaws.com
|
|
ManagedPolicyArns:
|
|
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
|
|
Policies:
|
|
- PolicyName: AccessAWSServices
|
|
PolicyDocument:
|
|
Version: '2012-10-17'
|
|
Statement:
|
|
- Effect: Allow
|
|
Action:
|
|
- s3:AbortMultipartUpload
|
|
- s3:GetObject
|
|
- s3:ListBucket
|
|
- s3:PutObject
|
|
- s3:DeleteObject
|
|
Resource:
|
|
- !Sub arn:${AWS::Partition}:s3:::${DataBucket}
|
|
- !Sub arn:${AWS::Partition}:s3:::${DataBucket}/*
|
|
- Effect: Allow
|
|
Action: dsql:DbConnectAdmin
|
|
Resource: !Sub arn:${AWS::Partition}:dsql:${AWS::Region}:${AWS::AccountId}:cluster/${DSQLClusterId}
|
|
- !If
|
|
- IsEmailEnabled
|
|
- Effect: Allow
|
|
Action:
|
|
- ses:SendEmail
|
|
- ses:SendRawEmail
|
|
Resource: '*'
|
|
Condition:
|
|
StringEquals:
|
|
ses:FromAddress: !Ref SMTPFrom
|
|
ses:FromDisplayName: !Ref SMTPFromName
|
|
- !Ref AWS::NoValue
|
|
|
|
ApiFunction:
|
|
Type: AWS::Lambda::Function
|
|
Properties:
|
|
Architectures:
|
|
- arm64
|
|
Code: ./vaultwarden-lambda.zip
|
|
Environment:
|
|
Variables:
|
|
AWS_LWA_PORT: 8000
|
|
AWS_LWA_READINESS_CHECK_PATH: /alive
|
|
AWS_LWA_ASYNC_INIT: true
|
|
AWS_LWA_ENABLE_COMPRESSION: true
|
|
AWS_LWA_INVOKE_MODE: RESPONSE_STREAM
|
|
DATA_FOLDER: !Sub s3://${DataBucket}
|
|
TMP_FOLDER: /tmp
|
|
DATABASE_URL: !Sub dsql://${DSQLClusterId}.dsql.${AWS::Region}.on.aws
|
|
ENABLE_WEBSOCKET: false
|
|
DOMAIN: !If
|
|
- IsDomainAndCertificateSet
|
|
- !Ref Domain
|
|
- !Ref AWS::NoValue
|
|
SIGNUPS_ALLOWED: !Ref SignupsAllowed
|
|
IP_HEADER: X-Forwarded-For
|
|
ICON_SERVICE: !Ref IconService
|
|
ICON_REDIRECT_CODE: 301
|
|
ADMIN_TOKEN: !If
|
|
- IsAdminTokenEmpty
|
|
- !Ref AWS::NoValue
|
|
- !Ref AdminToken
|
|
SMTP_FROM: !If
|
|
- IsEmailEnabled
|
|
- !Ref SMTPFrom
|
|
- !Ref AWS::NoValue
|
|
SMTP_FROM_NAME: !Ref SMTPFromName
|
|
USE_AWS_SES: !If
|
|
- IsEmailEnabled
|
|
- 'true'
|
|
- 'false'
|
|
FunctionName: !Sub ${AWS::StackName}-api
|
|
Handler: bootstrap
|
|
Layers:
|
|
- !Sub arn:aws:lambda:${AWS::Region}:753240598075:layer:LambdaAdapterLayerArm64:24
|
|
MemorySize: 3008 # Maximum value allowed for new accounts, higher value reduces cold start times, should still fit under free tier usage for personal use
|
|
Role: !GetAtt ApiFunctionRole.Arn
|
|
Runtime: provided.al2023
|
|
Timeout: 300
|
|
|
|
ApiFunctionLogs:
|
|
Type: AWS::Logs::LogGroup
|
|
DeletionPolicy: RetainExceptOnCreate
|
|
Properties:
|
|
LogGroupName: !Sub /aws/lambda/${ApiFunction}
|
|
RetentionInDays: !If
|
|
- IsApiLogRetentionNeverExpire
|
|
- !Ref AWS::NoValue
|
|
- !Ref APILogRetention
|
|
|
|
ApiFunctionUrl:
|
|
Type: AWS::Lambda::Url
|
|
Properties:
|
|
TargetFunctionArn: !Ref ApiFunction
|
|
AuthType: NONE
|
|
InvokeMode: RESPONSE_STREAM
|
|
|
|
ApiFunctionUrlPublicPermissions:
|
|
Type: AWS::Lambda::Permission
|
|
Properties:
|
|
Action: lambda:InvokeFunctionUrl
|
|
FunctionName: !Ref ApiFunction
|
|
Principal: '*'
|
|
FunctionUrlAuthType: NONE
|
|
|
|
WebVaultAssetsBucket:
|
|
Type: AWS::S3::Bucket
|
|
Properties:
|
|
BucketName: !Sub ${AWS::StackName}-${AWS::AccountId}-${AWS::Region}-web-vault
|
|
PublicAccessBlockConfiguration:
|
|
BlockPublicAcls: true
|
|
BlockPublicPolicy: true
|
|
IgnorePublicAcls: true
|
|
RestrictPublicBuckets: true
|
|
|
|
WebVaultAssetsBucketPolicies:
|
|
Type: AWS::S3::BucketPolicy
|
|
Properties:
|
|
Bucket: !Ref WebVaultAssetsBucket
|
|
PolicyDocument:
|
|
Version: '2012-10-17'
|
|
Statement:
|
|
- Sid: DenyUnencryptedTransit
|
|
Effect: Deny
|
|
Principal: '*'
|
|
Action: s3:*
|
|
Resource:
|
|
- !Sub arn:${AWS::Partition}:s3:::${WebVaultAssetsBucket}
|
|
- !Sub arn:${AWS::Partition}:s3:::${WebVaultAssetsBucket}/*
|
|
Condition:
|
|
Bool:
|
|
aws:SecureTransport: false
|
|
- Sid: AllowCloudFrontOriginAccessControlRead
|
|
Effect: Allow
|
|
Principal:
|
|
Service: !Sub cloudfront.${AWS::URLSuffix}
|
|
Action: s3:GetObject
|
|
Resource: !Sub ${WebVaultAssetsBucket.Arn}/*
|
|
Condition:
|
|
StringEquals:
|
|
AWS:SourceArn: !Sub arn:${AWS::Partition}:cloudfront::${AWS::AccountId}:distribution/${CDN.Id}
|
|
|
|
WebVaultAssetsBucketOriginAccessControl:
|
|
Type: AWS::CloudFront::OriginAccessControl
|
|
Properties:
|
|
OriginAccessControlConfig:
|
|
Name: !Sub ${AWS::StackName}-${AWS::Region}-web-vault-access-control
|
|
OriginAccessControlOriginType: s3
|
|
SigningBehavior: always
|
|
SigningProtocol: sigv4
|
|
|
|
# The following mirrors the header values in util.rs
|
|
ResponseHeaderPolicy:
|
|
Type: AWS::CloudFront::ResponseHeadersPolicy
|
|
Properties:
|
|
ResponseHeadersPolicyConfig:
|
|
Name: !Sub ${AWS::StackName}-${AWS::Region}
|
|
CustomHeadersConfig:
|
|
Items:
|
|
- Header: Cache-Control
|
|
Override: false
|
|
Value: no-cache, no-store, max-age=0
|
|
- Header: X-Robots-Tag
|
|
Override: true
|
|
Value: noindex, nofollow
|
|
- Header: Permissions-Policy
|
|
Override: true
|
|
Value: accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=()
|
|
SecurityHeadersConfig:
|
|
ContentSecurityPolicy:
|
|
ContentSecurityPolicy: !Sub
|
|
- >-
|
|
default-src 'none';
|
|
font-src 'self';
|
|
manifest-src 'self';
|
|
base-uri 'self';
|
|
form-action 'self';
|
|
media-src 'self';
|
|
object-src 'self' blob:;
|
|
script-src 'self' 'wasm-unsafe-eval';
|
|
style-src 'self' 'unsafe-inline';
|
|
child-src 'self' https://*.duosecurity.com https://*.duofederal.com;
|
|
frame-src 'self' https://*.duosecurity.com https://*.duofederal.com;
|
|
frame-ancestors 'self'
|
|
chrome-extension://nngceckbapebfimnlniiiahkandclblb
|
|
chrome-extension://jbkfoedolllekgbhcbcoahefnbanhhlh
|
|
moz-extension://*;
|
|
img-src 'self' data:
|
|
https://haveibeenpwned.com
|
|
${IconServiceCSP};
|
|
connect-src 'self'
|
|
https://api.pwnedpasswords.com
|
|
https://api.2fa.directory
|
|
https://app.simplelogin.io/api/
|
|
https://app.addy.io/api/
|
|
https://api.fastmail.com/
|
|
https://api.forwardemail.net
|
|
https://${DataBucket.RegionalDomainName};
|
|
- IconServiceCSP: !If
|
|
- IconSourceIsPredefined
|
|
- !FindInMap [IconSource, !Ref IconService, CSP]
|
|
- !Select
|
|
- 0
|
|
- !Split ['{', !Ref IconService]
|
|
Override: true
|
|
ContentTypeOptions:
|
|
Override: true
|
|
FrameOptions:
|
|
FrameOption: SAMEORIGIN
|
|
Override: true
|
|
ReferrerPolicy:
|
|
Override: true
|
|
ReferrerPolicy: same-origin
|
|
StrictTransportSecurity:
|
|
AccessControlMaxAgeSec: 63072000
|
|
IncludeSubdomains: true
|
|
Override: true
|
|
Preload: true
|
|
XSSProtection:
|
|
Override: true
|
|
Protection: false
|
|
|
|
# The following mirrors the header values in util.rs
|
|
ConnectorHtmlResponseHeaderPolicy:
|
|
Type: AWS::CloudFront::ResponseHeadersPolicy
|
|
Properties:
|
|
ResponseHeadersPolicyConfig:
|
|
Name: !Sub ${AWS::StackName}-${AWS::Region}-connector-html
|
|
CustomHeadersConfig:
|
|
Items:
|
|
- Header: Cache-Control
|
|
Override: true
|
|
Value: no-cache, no-store, max-age=0
|
|
- Header: X-Robots-Tag
|
|
Override: true
|
|
Value: noindex, nofollow
|
|
- Header: Permissions-Policy
|
|
Override: true
|
|
Value: accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=()
|
|
SecurityHeadersConfig:
|
|
ContentTypeOptions:
|
|
Override: true
|
|
ReferrerPolicy:
|
|
Override: true
|
|
ReferrerPolicy: same-origin
|
|
StrictTransportSecurity:
|
|
AccessControlMaxAgeSec: 63072000
|
|
IncludeSubdomains: true
|
|
Override: true
|
|
Preload: true
|
|
XSSProtection:
|
|
Override: true
|
|
Protection: false
|
|
|
|
CDN:
|
|
Type: AWS::CloudFront::Distribution
|
|
Properties:
|
|
DistributionConfig:
|
|
Aliases: !If
|
|
- IsDomainAndCertificateSet
|
|
- - !Select
|
|
- 2
|
|
- !Split
|
|
- /
|
|
- !Ref Domain
|
|
- !Ref AWS::NoValue
|
|
CacheBehaviors:
|
|
- AllowedMethods:
|
|
- DELETE
|
|
- HEAD
|
|
- GET
|
|
- OPTIONS
|
|
- PATCH
|
|
- POST
|
|
- PUT
|
|
CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad # CachingDisabled
|
|
Compress: true
|
|
OriginRequestPolicyId: b689b0a8-53d0-40ab-baf2-68738e2966ac # AllViewerExceptHostHeader
|
|
PathPattern: /api/*
|
|
ResponseHeadersPolicyId: !Ref ResponseHeaderPolicy
|
|
TargetOriginId: Api
|
|
ViewerProtocolPolicy: redirect-to-https
|
|
- AllowedMethods:
|
|
- DELETE
|
|
- HEAD
|
|
- GET
|
|
- OPTIONS
|
|
- PATCH
|
|
- POST
|
|
- PUT
|
|
CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad # CachingDisabled
|
|
Compress: true
|
|
OriginRequestPolicyId: b689b0a8-53d0-40ab-baf2-68738e2966ac # AllViewerExceptHostHeader
|
|
PathPattern: /admin
|
|
ResponseHeadersPolicyId: !Ref ResponseHeaderPolicy
|
|
TargetOriginId: Api
|
|
ViewerProtocolPolicy: redirect-to-https
|
|
- AllowedMethods:
|
|
- DELETE
|
|
- HEAD
|
|
- GET
|
|
- OPTIONS
|
|
- PATCH
|
|
- POST
|
|
- PUT
|
|
CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad # CachingDisabled
|
|
Compress: true
|
|
OriginRequestPolicyId: b689b0a8-53d0-40ab-baf2-68738e2966ac # AllViewerExceptHostHeader
|
|
PathPattern: /admin/*
|
|
ResponseHeadersPolicyId: !Ref ResponseHeaderPolicy
|
|
TargetOriginId: Api
|
|
ViewerProtocolPolicy: redirect-to-https
|
|
- AllowedMethods:
|
|
- DELETE
|
|
- HEAD
|
|
- GET
|
|
- OPTIONS
|
|
- PATCH
|
|
- POST
|
|
- PUT
|
|
CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad # CachingDisabled
|
|
Compress: true
|
|
OriginRequestPolicyId: b689b0a8-53d0-40ab-baf2-68738e2966ac # AllViewerExceptHostHeader
|
|
PathPattern: /events/*
|
|
ResponseHeadersPolicyId: !Ref ResponseHeaderPolicy
|
|
TargetOriginId: Api
|
|
ViewerProtocolPolicy: redirect-to-https
|
|
- AllowedMethods:
|
|
- DELETE
|
|
- HEAD
|
|
- GET
|
|
- OPTIONS
|
|
- PATCH
|
|
- POST
|
|
- PUT
|
|
CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad # CachingDisabled
|
|
Compress: true
|
|
OriginRequestPolicyId: b689b0a8-53d0-40ab-baf2-68738e2966ac # AllViewerExceptHostHeader
|
|
PathPattern: /identity/*
|
|
ResponseHeadersPolicyId: !Ref ResponseHeaderPolicy
|
|
TargetOriginId: Api
|
|
ViewerProtocolPolicy: redirect-to-https
|
|
- CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad # CachingDisabled
|
|
Compress: true
|
|
OriginRequestPolicyId: b689b0a8-53d0-40ab-baf2-68738e2966ac # AllViewerExceptHostHeader
|
|
PathPattern: /css/*
|
|
ResponseHeadersPolicyId: !Ref ResponseHeaderPolicy
|
|
TargetOriginId: Api
|
|
ViewerProtocolPolicy: redirect-to-https
|
|
- CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad # CachingDisabled
|
|
Compress: true
|
|
OriginRequestPolicyId: b689b0a8-53d0-40ab-baf2-68738e2966ac # AllViewerExceptHostHeader
|
|
PathPattern: /vw_static/*
|
|
ResponseHeadersPolicyId: !Ref ResponseHeaderPolicy
|
|
TargetOriginId: Api
|
|
ViewerProtocolPolicy: redirect-to-https
|
|
- CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6 # CachingOptimized
|
|
Compress: true
|
|
OriginRequestPolicyId: b689b0a8-53d0-40ab-baf2-68738e2966ac # AllViewerExceptHostHeader
|
|
PathPattern: /icons/*
|
|
ResponseHeadersPolicyId: !Ref ResponseHeaderPolicy
|
|
TargetOriginId: Api
|
|
ViewerProtocolPolicy: redirect-to-https
|
|
- CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad # CachingDisabled
|
|
Compress: true
|
|
PathPattern: '*.html'
|
|
ResponseHeadersPolicyId: !Ref ResponseHeaderPolicy
|
|
TargetOriginId: WebVaultAssetsBucket
|
|
ViewerProtocolPolicy: redirect-to-https
|
|
- CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad # CachingDisabled
|
|
Compress: true
|
|
PathPattern: '*connector.html'
|
|
ResponseHeadersPolicyId: !Ref ConnectorHtmlResponseHeaderPolicy
|
|
TargetOriginId: WebVaultAssetsBucket
|
|
ViewerProtocolPolicy: redirect-to-https
|
|
Comment: Vaultwarden CDN
|
|
CustomErrorResponses:
|
|
- ErrorCode: 403
|
|
ResponseCode: 200
|
|
ResponsePagePath: /404.html
|
|
DefaultCacheBehavior:
|
|
CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6 # CachingOptimized
|
|
Compress: true
|
|
ResponseHeadersPolicyId: !Ref ResponseHeaderPolicy
|
|
TargetOriginId: WebVaultAssetsBucket
|
|
ViewerProtocolPolicy: redirect-to-https
|
|
DefaultRootObject: index.html
|
|
Enabled: true
|
|
HttpVersion: http2and3
|
|
IPV6Enabled: true
|
|
Origins:
|
|
- Id: WebVaultAssetsBucket
|
|
DomainName: !GetAtt WebVaultAssetsBucket.RegionalDomainName
|
|
OriginAccessControlId: !GetAtt WebVaultAssetsBucketOriginAccessControl.Id
|
|
S3OriginConfig:
|
|
OriginAccessIdentity: ''
|
|
- Id: Api
|
|
CustomOriginConfig:
|
|
OriginProtocolPolicy: https-only
|
|
OriginSSLProtocols:
|
|
- TLSv1.2
|
|
DomainName: !Select
|
|
- 2
|
|
- !Split
|
|
- /
|
|
- !GetAtt ApiFunctionUrl.FunctionUrl
|
|
PriceClass: PriceClass_All
|
|
ViewerCertificate: !If
|
|
- IsDomainAndCertificateSet
|
|
- AcmCertificateArn: !Ref ACMCertificateArn
|
|
MinimumProtocolVersion: TLSv1.2_2021
|
|
SslSupportMethod: sni-only
|
|
- !Ref AWS::NoValue
|
|
|
|
Outputs:
|
|
WebVaultAssetsBucket:
|
|
Value: !Ref WebVaultAssetsBucket
|
|
CDNDomain:
|
|
Value: !GetAtt CDN.DomainName
|