Skip to content

Commit 1f0cb05

Browse files
authored
Merge pull request #73 from wwwehr/npw/custom-dns-route53
added custom domain route53 provider to dstack ingress
2 parents 681f00c + 4fe361e commit 1f0cb05

File tree

5 files changed

+642
-3
lines changed

5 files changed

+642
-3
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
AWSTemplateFormatVersion: '2010-09-09'
2+
3+
Parameters:
4+
HostedZoneId:
5+
Type: String
6+
Default:
7+
Description: Route53 Hosted Zone ID
8+
UserName:
9+
Type: String
10+
Description: IAM user that can only assume the Route53 role
11+
12+
Resources:
13+
User:
14+
Type: AWS::IAM::User
15+
Properties:
16+
UserName: !Ref UserName
17+
18+
AccessKey:
19+
Type: AWS::IAM::AccessKey
20+
Properties:
21+
UserName: !Ref User
22+
Status: Active
23+
24+
Route53Role:
25+
Type: AWS::IAM::Role
26+
Properties:
27+
RoleName: !Sub '${UserName}-route53-role'
28+
AssumeRolePolicyDocument:
29+
Version: '2012-10-17'
30+
Statement:
31+
- Effect: Allow
32+
# The *account root* as trusted principal.
33+
# This avoids invalid-principal errors while remaining safe,
34+
# because the USER policy enforces the actual restriction.
35+
Principal:
36+
AWS: !Sub arn:aws:iam::${AWS::AccountId}:root
37+
Action: sts:AssumeRole
38+
Policies:
39+
- PolicyName: Route53DnsChallenges
40+
PolicyDocument:
41+
Version: '2012-10-17'
42+
Statement:
43+
- Sid: AllowDnsChallengeChanges
44+
Effect: Allow
45+
Action:
46+
- route53:ChangeResourceRecordSets
47+
Resource: !Sub arn:aws:route53:::hostedzone/${HostedZoneId}
48+
- Sid: AllowListingForDnsChallenge
49+
Effect: Allow
50+
Action:
51+
- route53:ListHostedZonesByName
52+
- route53:ListHostedZones
53+
- route53:GetChange
54+
- route53:ListResourceRecordSets
55+
Resource: "*"
56+
57+
UserAssumeRolePolicy:
58+
Type: AWS::IAM::Policy
59+
Properties:
60+
PolicyName: !Sub '${UserName}-assume-route53-role'
61+
Users:
62+
- !Ref User
63+
PolicyDocument:
64+
Version: '2012-10-17'
65+
Statement:
66+
- Effect: Allow
67+
Action:
68+
- sts:AssumeRole
69+
Resource: !Sub arn:aws:iam::${AWS::AccountId}:role/${UserName}-route53-role
70+
71+
Outputs:
72+
AWSAccessKeyId:
73+
Description: Access key ID for the IAM user
74+
Value: !Ref AccessKey
75+
76+
AWSSecretAccessKey:
77+
Description: Secret access key for the IAM user
78+
Value: !GetAtt AccessKey.SecretAccessKey
79+
80+
AWSUserArn:
81+
Description: IAM User ARN
82+
Value: !Sub arn:aws:iam::${AWS::AccountId}:user/${UserName}
83+
84+
Route53RoleArn:
85+
Description: ARN of the Route53 role used by Certbot
86+
Value: !Sub arn:aws:iam::${AWS::AccountId}:role/${UserName}-route53-role

custom-domain/dstack-ingress/DNS_PROVIDERS.md

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ This guide explains how to configure dstack-ingress to work with different DNS p
77
- **Cloudflare** - The original and default provider
88
- **Linode DNS** - For Linode-hosted domains
99
- **Namecheap** - For Namecheap-hosted domains
10+
- **Route53** - For AWS hosted domains
1011

1112
## Environment Variables
1213

@@ -73,6 +74,40 @@ NAMECHEAP_CLIENT_IP=your-client-ip
7374
- Namecheap doesn't support CAA records through their API currently
7475
- The certbot plugin uses the format `certbot-dns-namecheap` package
7576

77+
### Route53
78+
79+
```bash
80+
DNS_PROVIDER=route53
81+
AWS_ACCESS_KEY_ID=service-account-key-that-can-assume-role
82+
AWS_SECRET_ACCESS_KEY=service-account-secret-that-can-assume-role
83+
AWS_ROLE_ARN=role-that-can-mod-route53
84+
AWS_REGION=your-closest-region
85+
```
86+
87+
**Required Permissions:**
88+
```yaml
89+
PolicyDocument:
90+
Version: '2012-10-17'
91+
Statement:
92+
- Sid: AllowDnsChallengeChanges
93+
Effect: Allow
94+
Action:
95+
- route53:ChangeResourceRecordSets
96+
Resource: !Sub arn:aws:route53:::hostedzone/${HostedZoneId}
97+
- Sid: AllowListingForDnsChallenge
98+
Effect: Allow
99+
Action:
100+
- route53:ListHostedZonesByName
101+
- route53:ListHostedZones
102+
- route53:GetChange
103+
- route53:ListResourceRecordSets
104+
```
105+
106+
**Important Notes for Route53:**
107+
- The certbot plugin uses the format `certbot-dns-route53` package
108+
- CAA will merge AWS & Let's Encrypt CA domains to existing records if they exist
109+
- It is essential that the AWS service account used can only assume the limited role. See cloudformation example.
110+
76111
## Docker Compose Examples
77112

78113
### Linode Example
@@ -127,6 +162,34 @@ services:
127162
- ./evidences:/evidences
128163
```
129164

165+
### Route53 Example
166+
167+
```yaml
168+
services:
169+
dstack-ingress:
170+
image: dstack-ingress:latest
171+
restart: unless-stopped
172+
volumes:
173+
- /var/run/dstack.sock:/var/run/dstack.sock
174+
- cert-data:/etc/letsencrypt
175+
ports:
176+
- 443:443
177+
environment:
178+
DNS_PROVIDER: route53
179+
DOMAIN: app.example.com
180+
GATEWAY_DOMAIN: _.${DSTACK_GATEWAY_DOMAIN}
181+
182+
AWS_REGION: ${AWS_REGION}
183+
AWS_ROLE_ARN: ${AWS_ROLE_ARN}
184+
AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
185+
AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
186+
187+
CERTBOT_EMAIL: ${CERTBOT_EMAIL}
188+
TARGET_ENDPOINT: http://backend:8080
189+
SET_CAA: 'true'
190+
191+
```
192+
130193
## Migration from Cloudflare-only Setup
131194

132195
If you're currently using the Cloudflare-only version:
@@ -166,4 +229,4 @@ Ensure your API tokens/credentials have the necessary permissions listed above f
166229
1. Go to https://ap.www.namecheap.com/settings/tools/api-access/
167230
2. Enable API access for your account
168231
3. Note down your API key and username
169-
4. Make sure your IP address is whitelisted in the API settings
232+
4. Make sure your IP address is whitelisted in the API settings

custom-domain/dstack-ingress/scripts/dns_providers/factory.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from .cloudflare import CloudflareDNSProvider
77
from .linode import LinodeDNSProvider
88
from .namecheap import NamecheapDNSProvider
9+
from .route53 import Route53DNSProvider
910

1011

1112
class DNSProviderFactory:
@@ -15,6 +16,7 @@ class DNSProviderFactory:
1516
"cloudflare": CloudflareDNSProvider,
1617
"linode": LinodeDNSProvider,
1718
"namecheap": NamecheapDNSProvider,
19+
"route53": Route53DNSProvider,
1820
}
1921

2022
@classmethod
@@ -67,4 +69,4 @@ def _detect_provider_type(cls) -> str:
6769
@classmethod
6870
def get_supported_providers(cls) -> list:
6971
"""Get list of supported DNS providers."""
70-
return list(cls.PROVIDERS.keys())
72+
return list(cls.PROVIDERS.keys())

0 commit comments

Comments
 (0)