Skip to content

Commit b638838

Browse files
authored
Merge pull request #99 from thand-io/cloudformation
addded cloudformation one-click deploy
2 parents a62d473 + dea3cb1 commit b638838

4 files changed

Lines changed: 326 additions & 1 deletion

File tree

.github/workflows/test-and-build.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ on:
99
- 'examples/**'
1010
- 'docs/**'
1111
- 'config/**'
12+
- 'deploy/**'
1213
pull_request:
1314
branches: [ main ]
1415
paths-ignore:
1516
- '**/README.md'
1617
- 'examples/**'
1718
- 'docs/**'
1819
- 'config/**'
20+
- 'deploy/**'
1921

2022
permissions:
2123
contents: write

deploy/aws/cloudformation.yaml

Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
AWSTemplateFormatVersion: '2010-09-09'
2+
Description: 'Deploy Thand Agent to AWS App Runner with required IAM roles, KMS, and Secrets Manager integration'
3+
4+
Parameters:
5+
ServiceName:
6+
Type: String
7+
Default: thand-agent
8+
Description: Name of the App Runner service
9+
10+
ImageUri:
11+
Type: String
12+
Description: ECR image URI with tag (e.g., 123456789012.dkr.ecr.us-east-1.amazonaws.com/thand-io/agent:latest)
13+
AllowedPattern: '^[0-9]{12}\.dkr\.ecr\.[a-z0-9-]+\.amazonaws\.com\/[a-zA-Z0-9\/_-]+:[a-zA-Z0-9\._-]+$'
14+
ConstraintDescription: Must be a valid ECR image URI with tag (e.g., account.dkr.ecr.region.amazonaws.com/repository:tag)
15+
16+
Port:
17+
Type: Number
18+
Default: 8080
19+
Description: Port the application listens on
20+
21+
CPU:
22+
Type: String
23+
Default: '2 vCPU'
24+
AllowedValues:
25+
- '0.25 vCPU'
26+
- '0.5 vCPU'
27+
- '1 vCPU'
28+
- '2 vCPU'
29+
- '4 vCPU'
30+
Description: CPU allocation (recommended 2 vCPU)
31+
32+
Memory:
33+
Type: String
34+
Default: '4 GB'
35+
AllowedValues:
36+
- '0.5 GB'
37+
- '1 GB'
38+
- '2 GB'
39+
- '3 GB'
40+
- '4 GB'
41+
- '6 GB'
42+
- '8 GB'
43+
- '10 GB'
44+
- '12 GB'
45+
Description: Memory allocation (recommended 4 GB minimum)
46+
47+
Resources:
48+
# KMS Key for Thand Agent encryption
49+
ThandKMSKey:
50+
Type: AWS::KMS::Key
51+
Properties:
52+
Description: Encryption key for Thand Agent
53+
KeyPolicy:
54+
Version: '2012-10-17'
55+
Statement:
56+
- Sid: Enable IAM User Permissions
57+
Effect: Allow
58+
Principal:
59+
AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root'
60+
Action: 'kms:*'
61+
Resource: '*'
62+
- Sid: Allow App Runner service role to use the key
63+
Effect: Allow
64+
Principal:
65+
Service: tasks.apprunner.amazonaws.com
66+
Action:
67+
- 'kms:Decrypt'
68+
- 'kms:Encrypt'
69+
- 'kms:ReEncrypt*'
70+
- 'kms:GenerateDataKey*'
71+
- 'kms:DescribeKey'
72+
Resource: '*'
73+
74+
ThandKMSKeyAlias:
75+
Type: AWS::KMS::Alias
76+
Properties:
77+
AliasName: !Sub 'alias/${ServiceName}'
78+
TargetKeyId: !Ref ThandKMSKey
79+
80+
# Secrets Manager secrets for Thand configuration
81+
ThandProvidersSecret:
82+
Type: AWS::SecretsManager::Secret
83+
Properties:
84+
Name: !Sub '${ServiceName}-providers'
85+
Description: Thand Agent providers configuration
86+
SecretString: !Sub |
87+
version: "1.0"
88+
providers:
89+
aws:
90+
name: AWS Default
91+
description: Default AWS provider using IAM role
92+
provider: aws
93+
enabled: true
94+
config:
95+
region: ${AWS::Region}
96+
97+
ThandRolesSecret:
98+
Type: AWS::SecretsManager::Secret
99+
Properties:
100+
Name: !Sub '${ServiceName}-roles'
101+
Description: Thand Agent roles configuration
102+
SecretString: |
103+
version: "1.0"
104+
roles: {}
105+
106+
ThandWorkflowsSecret:
107+
Type: AWS::SecretsManager::Secret
108+
Properties:
109+
Name: !Sub '${ServiceName}-workflows'
110+
Description: Thand Agent workflows configuration
111+
SecretString: |
112+
version: "1.0"
113+
workflows: {}
114+
115+
# IAM Role for App Runner to access ECR
116+
AppRunnerECRAccessRole:
117+
Type: AWS::IAM::Role
118+
Properties:
119+
RoleName: !Sub '${ServiceName}-ecr-access-role'
120+
AssumeRolePolicyDocument:
121+
Version: '2012-10-17'
122+
Statement:
123+
- Effect: Allow
124+
Principal:
125+
Service: build.apprunner.amazonaws.com
126+
Action: 'sts:AssumeRole'
127+
ManagedPolicyArns:
128+
- 'arn:aws:iam::aws:policy/service-role/AWSAppRunnerServicePolicyForECRAccess'
129+
Policies:
130+
- PolicyName: ECRImagePull
131+
PolicyDocument:
132+
Version: '2012-10-17'
133+
Statement:
134+
- Effect: Allow
135+
Action:
136+
- 'ecr:GetDownloadUrlForLayer'
137+
- 'ecr:BatchGetImage'
138+
- 'ecr:BatchCheckLayerAvailability'
139+
- 'ecr:DescribeRepositories'
140+
- 'ecr:GetRepositoryPolicy'
141+
- 'ecr:ListImages'
142+
Resource: '*'
143+
- Effect: Allow
144+
Action:
145+
- 'ecr:GetAuthorizationToken'
146+
Resource: '*'
147+
148+
# IAM Role for App Runner instance (runtime)
149+
AppRunnerInstanceRole:
150+
Type: AWS::IAM::Role
151+
Properties:
152+
RoleName: !Sub '${ServiceName}-instance-role'
153+
AssumeRolePolicyDocument:
154+
Version: '2012-10-17'
155+
Statement:
156+
- Effect: Allow
157+
Principal:
158+
Service: tasks.apprunner.amazonaws.com
159+
Action: 'sts:AssumeRole'
160+
ManagedPolicyArns:
161+
- 'arn:aws:iam::aws:policy/SecretsManagerReadWrite'
162+
- 'arn:aws:iam::aws:policy/AmazonSSMFullAccess'
163+
- 'arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess'
164+
- 'arn:aws:iam::aws:policy/IAMFullAccess'
165+
- 'arn:aws:iam::aws:policy/AWSSSOMasterAccountAdministrator'
166+
Policies:
167+
- PolicyName: KMSAccess
168+
PolicyDocument:
169+
Version: '2012-10-17'
170+
Statement:
171+
- Effect: Allow
172+
Action:
173+
- 'kms:Decrypt'
174+
- 'kms:Encrypt'
175+
- 'kms:ReEncrypt*'
176+
- 'kms:GenerateDataKey*'
177+
- 'kms:DescribeKey'
178+
- 'kms:CreateGrant'
179+
- 'kms:ListGrants'
180+
- 'kms:RevokeGrant'
181+
Resource: !GetAtt ThandKMSKey.Arn
182+
- PolicyName: CloudWatchLogs
183+
PolicyDocument:
184+
Version: '2012-10-17'
185+
Statement:
186+
- Effect: Allow
187+
Action:
188+
- 'logs:CreateLogGroup'
189+
- 'logs:CreateLogStream'
190+
- 'logs:PutLogEvents'
191+
Resource: '*'
192+
193+
# Auto Scaling Configuration
194+
AutoScalingConfig:
195+
Type: AWS::AppRunner::AutoScalingConfiguration
196+
Properties:
197+
AutoScalingConfigurationName: !Sub '${ServiceName}-autoscaling'
198+
MaxConcurrency: 100
199+
MaxSize: 10
200+
MinSize: 1
201+
202+
# App Runner Service
203+
AppRunnerService:
204+
Type: AWS::AppRunner::Service
205+
DependsOn:
206+
- ThandProvidersSecret
207+
- ThandRolesSecret
208+
- ThandWorkflowsSecret
209+
- ThandKMSKey
210+
Properties:
211+
ServiceName: !Ref ServiceName
212+
SourceConfiguration:
213+
AuthenticationConfiguration:
214+
AccessRoleArn: !GetAtt AppRunnerECRAccessRole.Arn
215+
ImageRepository:
216+
ImageIdentifier: !Ref ImageUri
217+
ImageRepositoryType: ECR
218+
ImageConfiguration:
219+
Port: !Ref Port
220+
RuntimeEnvironmentVariables:
221+
- Name: PORT
222+
Value: !Ref Port
223+
- Name: THAND_ENVIRONMENT_CONFIG_KMS_ARN
224+
Value: !GetAtt ThandKMSKey.Arn
225+
- Name: THAND_ENVIRONMENT_CONFIG_REGION
226+
Value: !Ref AWS::Region
227+
- Name: THAND_PROVIDERS_VAULT
228+
Value: !Sub '${ServiceName}-providers'
229+
- Name: THAND_ROLES_VAULT
230+
Value: !Sub '${ServiceName}-roles'
231+
- Name: THAND_WORKFLOWS_VAULT
232+
Value: !Sub '${ServiceName}-workflows'
233+
- Name: THAND_ENVIRONMENT_PLATFORM
234+
Value: aws
235+
InstanceConfiguration:
236+
Cpu: !Ref CPU
237+
Memory: !Ref Memory
238+
InstanceRoleArn: !GetAtt AppRunnerInstanceRole.Arn
239+
HealthCheckConfiguration:
240+
Protocol: HTTP
241+
Path: /health
242+
Interval: 10
243+
Timeout: 5
244+
HealthyThreshold: 1
245+
UnhealthyThreshold: 5
246+
AutoScalingConfigurationArn: !GetAtt AutoScalingConfig.AutoScalingConfigurationArn
247+
248+
Outputs:
249+
ServiceUrl:
250+
Description: App Runner service URL (use this for THAND_LOGIN_ENDPOINT)
251+
Value: !Sub 'https://${AppRunnerService.ServiceUrl}'
252+
Export:
253+
Name: !Sub '${AWS::StackName}-ServiceUrl'
254+
255+
ServiceArn:
256+
Description: App Runner service ARN
257+
Value: !GetAtt AppRunnerService.ServiceArn
258+
Export:
259+
Name: !Sub '${AWS::StackName}-ServiceArn'
260+
261+
ServiceId:
262+
Description: App Runner service ID
263+
Value: !GetAtt AppRunnerService.ServiceId
264+
Export:
265+
Name: !Sub '${AWS::StackName}-ServiceId'
266+
267+
ECRAccessRoleArn:
268+
Description: ECR Access Role ARN
269+
Value: !GetAtt AppRunnerECRAccessRole.Arn
270+
Export:
271+
Name: !Sub '${AWS::StackName}-ECRAccessRoleArn'
272+
273+
InstanceRoleArn:
274+
Description: Instance Role ARN (use this role for AWS provider configurations)
275+
Value: !GetAtt AppRunnerInstanceRole.Arn
276+
Export:
277+
Name: !Sub '${AWS::StackName}-InstanceRoleArn'
278+
279+
KMSKeyArn:
280+
Description: KMS Key ARN for encryption
281+
Value: !GetAtt ThandKMSKey.Arn
282+
Export:
283+
Name: !Sub '${AWS::StackName}-KMSKeyArn'
284+
285+
KMSKeyAlias:
286+
Description: KMS Key Alias
287+
Value: !Ref ThandKMSKeyAlias
288+
Export:
289+
Name: !Sub '${AWS::StackName}-KMSKeyAlias'
290+
291+
ProvidersSecretName:
292+
Description: Secrets Manager secret name for providers configuration
293+
Value: !Ref ThandProvidersSecret
294+
Export:
295+
Name: !Sub '${AWS::StackName}-ProvidersSecret'
296+
297+
RolesSecretName:
298+
Description: Secrets Manager secret name for roles configuration
299+
Value: !Ref ThandRolesSecret
300+
Export:
301+
Name: !Sub '${AWS::StackName}-RolesSecret'
302+
303+
WorkflowsSecretName:
304+
Description: Secrets Manager secret name for workflows configuration
305+
Value: !Ref ThandWorkflowsSecret
306+
Export:
307+
Name: !Sub '${AWS::StackName}-WorkflowsSecret'
308+
309+
LoginCommand:
310+
Description: CLI login command
311+
Value: !Sub 'thand login --login-server https://${AppRunnerService.ServiceUrl}'

deploy/aws/deploy.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# You will need to first build and push the Docker image to ECR.
2+
# Replace the ImageUri parameter value with your ECR image URI.
3+
4+
aws cloudformation deploy \
5+
--template-file cloudformation.yaml \
6+
--stack-name thand-agent \
7+
--parameter-overrides \
8+
ImageUri=12345.dkr.ecr.us-east-1.amazonaws.com/thand-io/agent:latest \
9+
ProvidersConfig="$(cat providers.yaml)" \
10+
RolesConfig="$(cat roles.yaml)" \
11+
WorkflowsConfig="$(cat workflows.yaml)" \
12+
--capabilities CAPABILITY_NAMED_IAM

docs/configuration/providers/email.ses/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ The AWS SES email provider (`email.ses`) enables email notifications through Ama
3434
| `access_key_id` | string | No | AWS access key ID for static credentials |
3535
| `secret_access_key` | string | No | AWS secret access key for static credentials |
3636
| `endpoint` | string | No | Custom endpoint URL (e.g., for LocalStack testing) |
37-
| `imsd_disable` | boolean | No | Disable EC2 IMDSv2 for credential retrieval |
37+
| `imds_disable` | boolean | No | Disable EC2 IMDSv2 for credential retrieval |
3838

3939
## Authentication Methods
4040

0 commit comments

Comments
 (0)