@@ -125,19 +125,49 @@ export class BackendStack extends cdk.Stack {
125125 'Allow inbound HTTPS traffic from within VPC' ,
126126 ) ;
127127
128- // Task Definition
128+ // Create Task Execution Role - this is used during task startup
129+ const taskExecutionRole = new iam . Role ( this , `${ appName } TaskExecutionRole-${ props . environment } ` , {
130+ assumedBy : new iam . ServicePrincipal ( 'ecs-tasks.amazonaws.com' ) ,
131+ description : 'Role that the ECS service uses to pull container images and publish logs to CloudWatch' ,
132+ managedPolicies : [
133+ iam . ManagedPolicy . fromAwsManagedPolicyName ( 'service-role/AmazonECSTaskExecutionRolePolicy' )
134+ ]
135+ } ) ;
136+
137+ // Create Task Role - this is used by the container during runtime
138+ const taskRole = new iam . Role ( this , `${ appName } TaskRole-${ props . environment } ` , {
139+ assumedBy : new iam . ServicePrincipal ( 'ecs-tasks.amazonaws.com' ) ,
140+ description : 'Role that the containers in the task assume' ,
141+ } ) ;
142+
143+ // Grant permissions to the task role
144+ // DynamoDB permissions
145+ reportsTable . grantReadWriteData ( taskRole ) ;
146+
147+ // Add permission to read Perplexity API key from Secrets Manager
148+ taskRole . addToPolicy ( new iam . PolicyStatement ( {
149+ effect : iam . Effect . ALLOW ,
150+ actions : [
151+ 'secretsmanager:GetSecretValue' ,
152+ 'secretsmanager:DescribeSecret'
153+ ] ,
154+ resources : [
155+ `arn:aws:secretsmanager:${ this . region } :${ this . account } :secret:medical-reports-explainer/${ props . environment } /perplexity-api-key-*`
156+ ]
157+ } ) ) ;
158+
159+ // Task Definition with explicit roles
129160 const taskDefinition = new ecs . FargateTaskDefinition (
130161 this ,
131162 `${ appName } TaskDef-${ props . environment } ` ,
132163 {
133164 memoryLimitMiB : isProd ? 1024 : 512 ,
134165 cpu : isProd ? 512 : 256 ,
166+ taskRole : taskRole , // Role that the application uses to call AWS services
167+ executionRole : taskExecutionRole // Role that ECS uses to pull images and write logs
135168 } ,
136169 ) ;
137170
138- // Grant DynamoDB permissions to task
139- reportsTable . grantReadWriteData ( taskDefinition . taskRole ) ;
140-
141171 // Create a secrets manager for the SSL certificate and key
142172 const certificateSecret = new cdk . aws_secretsmanager . Secret (
143173 this ,
@@ -194,7 +224,7 @@ export class BackendStack extends cdk.Stack {
194224 } ) ;
195225
196226 // Grant the task role access to read the SSL certificate secret
197- certificateSecret . grantRead ( taskDefinition . taskRole ) ;
227+ certificateSecret . grantRead ( taskRole ) ;
198228
199229 container . addPortMappings ( {
200230 containerPort : 3000 ,
0 commit comments