-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Description
Describe the bug
The SourcedConfiguration construct does not make use of it's retrievalRole property regardless of wether is defined or not. It will always create a new IAM Role (except when it's location type is ConfigurationSourceType.CODE_PIPELINE then it will default to undefined).
I encountered this behavior while trying to use role of mine created in a different stack and encountered an error that the role used was not allowed to retrieve the secret my configuration profile should reference.
Expected Behavior
The SourcedConfiguration should make use of the role passed to it via the retrievalRole property.
Current Behavior
The SourcedConfiguration will always create a new IAM Role instead of using the role passed into it via the retrievalRole property.
Reproduction Steps
- Create a secretmanager.Secret in Stack A.
- Create a iam.Role in Stack A and grant it read access rights to the secret.
- Deploy Stack A.
- Import the Secret from Stack A via Secret.fromSecretNameV2 function into Stack B.
- Import the Role from Stack A via Role.fromRoleName function into Stack B.
- Create a appconfig.SourcedConfiguration in Stack B referencing the imported Secret as location and the imported Role as retrievalRole.
- Try Deploy Stack B. You should experience and access denied error. The logs will also reference a different iam.Role. You can also debug the SourcedConfiguration initialization and see that a new role will be created even though a retrievalRole was passed into the construct.
Here a simplyfied version of my code:
StackA:
import {Stack, StackProps} from "aws-cdk-lib";
import {Construct} from "constructs";
import {Role, ServicePrincipal} from "aws-cdk-lib/aws-iam";
import {Secret} from "aws-cdk-lib/aws-secretsmanager";
export class StackA extends Stack {
constructor(scope: Construct, id: string, props: StackProps) {
super(scope, id, props);
const appConfigRetrievalRole = new Role(this, 'AppConfigRetrieveRole', {
assumedBy: new ServicePrincipal('appconfig.amazonaws.com'),
roleName: 'AppConfigRetrieveRole',
});
const mySecret = new Secret(this, 'MySecret', {
secretName: 'MySecret',
generateSecretString: {
secretStringTemplate: JSON.stringify({
username: 'admin',
password: '<PASSWORD>'
}),
generateStringKey: 'password'
}
});
mySecret.grantRead(appConfigRetrievalRole);
}
}
StackB:
import {Construct} from "constructs";
import {Stack, StackProps} from "aws-cdk-lib";
import {Secret} from "aws-cdk-lib/aws-secretsmanager";
import {Application, ConfigurationSource, Environment, SourcedConfiguration} from "aws-cdk-lib/aws-appconfig";
import {Role} from "aws-cdk-lib/aws-iam";
export class StackB extends Stack {
constructor(scope: Construct, id: string, props: StackProps) {
super(scope, id, props);
const myAppConfigApp = new Application(this, 'MyAppConfigApp', {
applicationName: 'my-app',
})
const devEnv = new Environment(this, 'DevEnv', {
application: myAppConfigApp,
environmentName: 'dev',
});
const mySecret = Secret.fromSecretNameV2(this, 'MySecret', 'MySecret');
const appConfigRetrievalRole = Role.fromRoleName(this, 'AppConfigRetrieveRole', 'AppConfigRetrieveRole');
new SourcedConfiguration(this, 'MySecretConfig', {
name: 'mySecretConfig',
application: myAppConfigApp,
location: ConfigurationSource.fromSecret(mySecret),
retrievalRole: appConfigRetrievalRole,
});
}
}
Possible Solution
The condition in the SourcedConfigurations constructor checking wether the retrievalRole is defined is wrong. As I already wrote, regardless of wether retrievalRole is defined or not. It will always create a new IAM Role (except when it's location type is ConfigurationSourceType.CODE_PIPELINE then it will default to undefined). This makes no sense. If the retrievalRole is defined it should use this role.
Additional Information/Context
No response
CDK CLI Version
2.146.0
Framework Version
No response
Node.js Version
20.14.0
OS
Windows 10
Language
TypeScript
Language Version
No response
Other information
No response