I am using the new higher level GraphqlAPI class instead of the lower level constructs to create my Appsync api and connect it to a table.
this.api = new GraphqlApi(...);
The new GraphqlApi instance allows you to simply add datasources:
this.api.addDynamoDbDataSource('name', tableRef);
If you look at the example code at https://docs.aws.amazon.com/cdk/api/latest/docs/aws-appsync-readme.html, I notice that they do not create a role to grant permission for Appsync to access the table:
const itemsTableRole = new Role(this, 'ItemsDynamoDBRole', {
assumedBy: new ServicePrincipal('appsync.amazonaws.com')
});
This snippet I got from this example: https://github.com/aws-samples/aws-cdk-examples/blob/master/typescript/appsync-graphql-dynamodb/index.ts
In that example they still use the CfnGraphQLApi construct.
So there they are adding the role and the are adding a policy to the role for a table with permission to do specific actions. Which makes sense.
So my question is, when using the GrahpQl class, if I don't add a Role I can't execute my queries. And if I don't add permissions like:
this.appSyncRole.addToPolicy(new PolicyStatement({
actions: ['dynamodb:*'],
resources: [`${table.tableArn}/index/*`],
effect: Effect.ALLOW
}));
then I am getting an error like:
"message":"User: arn:aws:sts::[ACCOUNT]:assumed-role/[ROLENAME]/APPSYNC_ASSUME_ROLE is not authorized to perform: dynamodb:Query on resource: arn:aws:dynamodb[REGION]:[ACCOUNT]:table/[TABLENAME]/index/byEmail
So is this example for GrahpqlQl not complete or am I missing something else?
Related
I have external-secrets operator v0.5.1 installed and working with a SecretStore for retrieve AWS parameter store. Also tried updating to V0.5.8
This is working fine with IRSA but if I try to create a external-secret for AWS secrets, with a new SecretStore, the SecretStore' status is Valid but the ExternalSecret that references this SecretStore got the following error: SecretSyncedError
AccessDeniedException: User: arn:aws:sts::12345678:assumed-role/eks-backend-role-pre/external-secrets-provider-aws is not authorized to perform: secretsmanager:GetSecretValue on resource: /backend/pre/PRE_PRIVPGPKEY because no identity-based policy allows the secretsmanager:GetSecretValue action status code: 400,
Please, note the STS is trying to use eks-backend-role-pre/external-secrets-provider-aws which it doesn't exist. The role which exist is eks-backend-role-pre I'm not sure who is adding the suffix external-secrets-provider-aws which invalidate the role name.
Both SecretStore, the one dedicated to AWS Parameter Store and the other that is dedicated to gather from AWS Secrets has the same service account associated.
Why is working one External Secret and the other using the same service account don't?
There was a typo in the policy.
As documentation shows, this is the correct way to declare a principal:
arn:${Partition}:secretsmanager:${Region}:${Account}:secret:${SecretId}
I have incorrect declared the principal:
"arn:aws:secretsmanager:eu-west-1:1234567890:secret/backend/pre/*"
Correct:
"arn:aws:secretsmanager:eu-west-1:1234567890:secret:/backend/pre/*"
In contrast to SSM Parameter store that you declare your principal "arn:aws:ssm:eu-west-1:1234567890:parameter/backend/pre/*"
, with SecretsManager you need to add a colon after the service :secret:
This stack was working at one point... I'm not sure what's going on. This permission is no longer doing what it did before, or has become invalid.
I have a Lambda function that rotates a Secret, so naturally it must be triggered by Secrets Manager. So I built up the Permission as follows
import * as aws from '#pulumi/aws'
export const accessTokenSecret = new aws.secretsmanager.Secret('accessTokenSecret', {});
export const smPermission = new aws.lambda.Permission(`${lambdaName}SecretsManagerPermission`, {
action: 'lambda:InvokeFunction',
function: rotateKnacklyAccessTokenLambda.name,
principal: 'secretsmanager.amazonaws.com',
sourceArn: accessTokenSecret.arn,
})
And the Policy,
{
Action: [
'secretsmanager:GetResourcePolicy',
'secretsmanager:GetSecretValue',
'secretsmanager:DescribeSecret',
'secretsmanager:ListSecrets',
'secretsmanager:RotateSecret',
],
Resource: 'arn:aws:secretsmanager:*:*:*',
Effect: 'Allow',
},
Running pulumi up -y yields
aws:secretsmanager:SecretRotation (knacklyAccessTokenRotation):
error: 1 error occurred:
* error enabling Secrets Manager Secret "" rotation: AccessDeniedException: Secrets Manager cannot invoke the specified Lambda function. Ensure that the function policy grants access to the principal secretsmanager.amazonaws.com.
This error confuses me, because the Policy created for the Lambda will not accept the Principal param (which makes sense, the same behaviour happens in the AWS Console), so I'm sure they mean Permission instead of Policy.
Based on the log I can tell that the Permission is being created way after the Lambda/Secrets Manager is, I'm not sure if this is a Pulumi issue similar to how it destroys stacks in the incorrect order (Roles and Policies for example).
I can see the Permission in the AWS Lambda configuration section, so maybe it's ok?
I'm trying to use AWS CDK to create a new lambda tied to already existing AWS resources which were not created using CDK and that are part of a different stack.
Can I trigger my lambda from an already existing user pool using CDK? I've imported the user pool to my new stack using:
const userPool = UserPool.fromUserPoolArn(this, 'poolName, 'arn:aws:cognito-idp:eu-west-1:1234567890:userpool/poolName')
However, this gives me an IUserPool which does not have the addTrigger method. Is there a way to convert this into a UserPool in order to be able to trigger the lambda (since I can see that UserPool has the addTrigger method)?
I have seen that it is possible to e.g. grant permissions for my new lambda to read/write into an existing DynamoDB table using CDK. And I don't really understand the difference here: DynamoDB is an existing AWS resource and I'm importing it to the new stack using CDK and then allowing my new lambda to modify it. The Cognito User Pool is also an existing AWS resource, and I am able to import it in CDK but it seems that I'm not able to modify it? Why?
This was discussed in this issue. You can add triggers to an existing User Pool using a Custom Resource:
import * as CustomResources from '#aws-cdk/custom-resources';
import * as Cognito from '#aws-cdk/aws-cognito';
import * as Iam from '#aws-cdk/aws-iam';
const userPool = Cognito.UserPool.fromUserPoolId(this, "UserPool", userPoolId);
new CustomResources.AwsCustomResource(this, "UpdateUserPool", {
resourceType: "Custom::UpdateUserPool",
onCreate: {
region: this.region,
service: "CognitoIdentityServiceProvider",
action: "updateUserPool",
parameters: {
UserPoolId: userPool.userPoolId,
LambdaConfig: {
PreSignUp: preSignUpHandler.functionArn
},
},
physicalResourceId: CustomResources.PhysicalResourceId.of(userPool.userPoolId),
},
policy: CustomResources.AwsCustomResourcePolicy.fromSdkCalls({ resources: CustomResources.AwsCustomResourcePolicy.ANY_RESOURCE }),
});
const invokeCognitoTriggerPermission = {
principal: new Iam.ServicePrincipal('cognito-idp.amazonaws.com'),
sourceArn: userPool.userPoolArn
}
preSignUpHandler.addPermission('InvokePreSignUpHandlerPermission', invokeCognitoTriggerPermission)
You can also modify other User Pool settings with this method.
I tried to replace one of the tables in my Appsync API, and now I'm getting this error:
User: arn:aws:sts::164370900240:assumed-role/User-role-likbfqoe4zd3zd7bz5bl2y4z6i-test/APPSYNC_ASSUME_ROLE is not authorized to perform: dynamodb:PutItem on resource: arn:aws:dynamodb:us-east-1:164370900240:table/User-site-test (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: AccessDeniedException; Request ID: ...)
I have no idea how to fix this. I don't see an IAM role with that ID. What should I do?
It seems like the IAM role that you assigned to the AppSync data source, that is used by AppSync to call your DynamoDB table on your behalf, has an old policy that gives it permission to the old table but not the new table. To figure out if this is that case, you can go to the AppSync console's data source page, select the data source in question and take note of the name of the role that is assigned to the data source. Once you have the name of the IAM role, go to the the IAM console, select the role, and edit the policy. If the name of the table in the policy does not match that of your new table, then update it.
Another option is to delete the data source from AppSync and then recreate it while telling the console to make a new role for you. The new role will be correctly scoped to the new table automatically when created through the AppSync console.
Can someone explain to me the difference between an AWS Policy and an AWS Managed Policy in the context of Cloud Formation?
More specifically, I'm trying to define an auto scaling template where:
Each instance in an auto scale configuration is assigned an IAM Instance Role that has a policy.
The same policy is applied to the user when they try and access these instances.
I'm trying to keep duplication to a minimum and it seems like I may be able to achieve it via a Policy linked to a role, and group of users. The role can then be associated with EC2 Instance via instance profile and users can be added to the groups which in turn are assigned the policy.
Why and under what circumstances would one use a ManagedPolicy?
Thank you for your assistance.
EDIT: It seems like Role requires a policy document irrespective. So even having a separate policy won't really help? Or am I missing something?
AWS::IAM::Role only requires a trust policy. The Policy/Managed Policy can be defined separately.
The difference between AWS::IAM::ManagedPolicy and AWS::IAM::Policy is that AWS::IAM::ManagedPolicy does not require you to assign a Group, Role or User when defining it. AWS::IAM::Policy does. In your use case, you're probably fine using AWS::IAM::Policy.
If I may add, testing Policy creation using CDK v2.12.0, groups, users or roles are not required. iam.ManagedPolicy creates a policy you can share, iam.Policy is created as an inline policy.
new iam.Policy(this, 'testPolicy2', {
statements: policyDocs,
//groups: [s3UserGroup],
policyName: 'testPolicy2'
})
new iam.ManagedPolicy(this, 'testPolicy3', {
statements: policyDocs,
//groups: [s3UserGroup],
managedPolicyName: 'testPolicy3'
})