Give KMS access permission to Proxy - amazon-web-services

I want to give the decrypt permission for proxy.
This proxy uses the a key in secret manager as username/password store.
and it uses key in KMS as Encryption key
This code makes role to acceess the secret manager automatically, but not KMS for decryption.
const dbProxy = new rds.DatabaseProxy(this, 'Proxy', {
proxyTarget: rds.ProxyTarget.fromCluster(dbCluster),
dbProxyName: `vr-${targetEnv}-rds-proxy`,
secrets: [dbCluster.secret!],// it makes the role to access the secret manager automatically.
securityGroups:[proxySecurityGroup],
requireTLS:false,
iamAuth:false,
vpc,
});
const kmsPolicy = new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ["kms:Decrypt"],
resources: ["*"],
})
dbProxy.addToRolePolicy(kmsPolicy)
However, there comes this error.
Property 'addToRolePolicy' does not exist on type 'DatabaseProxy'
I want to fetch the default created role and add this kmsPolicy
I tried this too.
const mainEncSecretArn = kms.Key.fromKeyArn(this, "kms-key", "arn:aws:kms:ap-northeast-1:665852837485:key/bf3cf318-1376-44de-a014-181074f4899d");
mainEncSecretArn.grantDecrypt(dbProxy);
The error is
Argument of type 'DatabaseProxy' is not assignable to parameter of type 'IGrantable'.
Property 'grantPrincipal' is missing in type 'DatabaseProxy' but required in type 'IGrantable'.

After working today with AWS Support, i was told (verbatim):
I would suggest explicitly defining the KMS permissions in a IAM policy document rather than using the "fromAliasName" Function.
I have provided some references that should help you write and attach the necessary KMS permission policy that is equivalent to the one that would have been created by the "fromAliasName" Function
And here is manual version of what support is saying cannot be done with cdk yet:
// get your kms key arn:
const kmsKeyArn =
'arn:aws:kms:us-west-2:123456789012:key/12345678-1234-1234-1234-1234567890';
// you won't be able to use the default proxy role :(
const proxyRole = new iam.Role(this, 'proxy-role', {
assumedBy: new iam.ServicePrincipal('rds.amazonaws.com'),
});
proxyRole.attachInlinePolicy(
new iam.Policy(this, 'kms-proxy-decrypt-policy', {
statements: [
new iam.PolicyStatement({
// grant the permission:
actions: ['kms:Decrypt'],
// put your kms key arn here:
resources: [kmsKeyArn],
}),
],
})
);
const proxy = new rds.DatabaseProxy(this, 'db-proxy', {
// there is other stuff here:
...
// ..but assign the role here:
role: proxyRole,
})

Related

How to Reuse the api gate TokenAuthorizer

I want to reuse the TokenAuthorizer which I have created in another stack. If a do the below it gives an error that it already exists, and if I change the authorizerName it creates a new one.
Is there a way I can reuse this resource?
const authzHandler = lambda.Function.fromFunctionName(this, 'AuthHandlerLookup', 'auth-handler');
const authorizer = new apigateway.TokenAuthorizer(this, 'WebApiTokenAuthorizer', {
handler: authzHandler,
resultsCacheTtl: Duration.seconds(600),
authorizerName: 'test-Authorizer',
assumeRole: lambdaExecutionRole
});
test.addMethod('GET', new apigateway.LambdaIntegration(TestLambda , { proxy: true }),
{
authorizer
}
i am able to get the authorizer information in cli , but now sure how to do the same using cdk
aws apigateway get-authorizer --rest-api-id wrrt25mzme0m --authorizer-id vffawds

Set cognito identity pool providers role resolution via Terraform

im trying to deploy cognito for opensearch via terraform. I have a manually built cognito working and ow trying to port it to terraform.
does anyone know how to set the below part?:
Choose role from token
role resolution 'DENY'
Terraform for the identity pool:
resource "aws_cognito_identity_pool" "cognito-identity-pool" {
identity_pool_name = "opensearch-${var.domain_name}-identity-pool"
allow_unauthenticated_identities = false
cognito_identity_providers {
client_id = aws_cognito_user_pool_client.cognito-user-pool-client.id
provider_name = aws_cognito_user_pool.cognito-user-pool.endpoint
}
}
ive tried adding server_side_token_check = false but no joy..
You need to use a different resource, namely aws_cognito_identity_pool_roles_attachment [1]. In order to achieve the same thing you see in the AWS console, you need to add the following block:
resource "aws_cognito_identity_pool_roles_attachment" "name" {
identity_pool_id = aws_cognito_identity_pool.cognito-identity-pool.id
roles = {
"authenticated" = <your-role-arn>
}
role_mapping {
ambiguous_role_resolution = "Deny"
type = "Token"
identity_provider = "${aws_cognito_user_pool.cognito-user-pool.endpoint}:${aws_cognito_user_pool_client.cognito-user-pool-client.id}"
}
}
Note that the roles block is required and the key can be authenticated or unathenticated. Additionally, you will probably have to figure out what kind of permissions the role will need and create it. The example in the documentation can be used as a blueprint. There are also other settings like mapping_rule block which might be of use to you, but since the details are lacking I omitted it from the answer.
[1] https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cognito_identity_pool_roles_attachment

Why codepipline require the KMS key?

I made the CodePipeline to build the source code from CodeCommit to ECR by cdk
When deploying this cdk code, somehow the key named like this
codepipeline-cdkmynavirepomynavipipelinefe7f8d68 is made in KMS customer managed key
I am not sure why this is made, and I don't want to use this.
Why or where this key is made?
const adminPipeline = new codepipeline.Pipeline(this, 'mynaviPipeline', {
pipelineName: 'cdk-mynavi-pl',
});
const mynavi_cc_repo_name = 'cdk-mynavi-cc'
const mynavi_cc_repo = new codecommit.Repository(this,
"mynavi-cc-repo",{
repositoryName: mynavi_cc_repo_name,
description:"for resizer repo"
})
const adminBuildProject = new codebuild.PipelineProject(this, 'adminBuildproject', {
environment: {
buildImage:codebuild.LinuxBuildImage.STANDARD_4_0,
privileged:true,
},
buildSpec: codebuild.BuildSpec.fromSourceFilename("./buildspec.yml")
});
const adminSourceOutput = new codepipeline.Artifact();
const adminSourceAction = new cdk.aws_codepipeline_actions.CodeCommitSourceAction({
actionName: 'AdminSource',
repository: mynavi_cc_repo,
output: adminSourceOutput,
trigger: cdk.aws_codepipeline_actions.CodeCommitTrigger.POLL,
})
const dockerHubSecretArn = 'arn:aws:secretsmanager:ap-northeast-1:678100228231:secret:docker_login-TBFA5B';
const dockerHubSecret = secretsmanager.Secret.fromSecretCompleteArn(this, 'SecretFromCompleteArn', dockerHubSecretArn);
dockerHubSecret.grantRead(adminBuildProject)
cronEcrRepo.grantPullPush(adminBuildProject)
djangoEcrRepo.grantPullPush(adminBuildProject)
nginxEcrRepo.grantPullPush(adminBuildProject)
const adminBuildOutput = new codepipeline.Artifact();
const adminBuildAction = new cdk.aws_codepipeline_actions.CodeBuildAction({
actionName: 'AdminCodeBuild',
project: adminBuildProject,
input: adminSourceOutput,
outputs: [adminBuildOutput]
});
adminPipeline.addStage({
stageName: "mynaviSource",
actions: [adminSourceAction],
});
adminPipeline.addStage({
stageName : "mynaviBuild",
actions: [adminBuildAction]
});
It has to do with encryption at rest.
Data in CodePipeline is encrypted at rest using AWS KMS keys. Code artifacts are stored in a customer-owned S3 bucket and encrypted with either the AWS managed key or a customer managed key.
Encrypting codepipline artifacts is enabled by default.
If you choose the default option for encrypting code artifacts, CodePipeline uses the AWS managed key. You cannot change or delete this AWS managed key.
You cannot disable the encryption, but you can choose how you encrypt the artifacts.
The good thing is that if you go with the default option, you don't have to manage the encryption keys.
This can be, for example, selected in the CodePipeline console:
More on Data Protection in AWS CodePipeline.

Rejected to connect from lambda to cognito due to not authorized

If CognitoIdentityProvider::Client doesn't provide access_key_id and secret_access_key, it will retrieve from the ENV by default.
The strange thing is it works at a totally new lambda but not in another.
client = Aws::CognitoIdentityProvider::Client.new(region: ENV['AWS_REGION'])
client.admin_get_user({
user_pool_id: Jets.application.config.cognito[:user_pool_id],
username: 'username'
})
I would get this error message but had no idea where can I set the policy for cognito.
"errorMessage": "User: arn:aws:sts::123123123123:assumed-role/firstage-api-stag-IamRole-1DYOOEVSCURMY/xxxxxx-api-stag-mes_controller-show is not authorized to perform: cognito-idp:AdminGetUser on resource: arn:aws:cognito-idp:ap-northeast-2:319924209672:userpool/ap-northeast-2_0cSCFMK4r",
"errorType": "Function<Aws::CognitoIdentityProvider::Errors::AccessDeniedException>",
I would like to use the default key_id and access_key in the lambda ENV rather than IAM user.
What should I do???
Best practice for Lambda functions is to ensure your IAM role associated with the Lambda function has the policy to let it invoke the specific AWS Service. Do not hard code creds in Lambda functions.
For some services, you need to write a custom policy. For example, for Pinpoint voice, you need to write a custom policy using JSON so the Lambda function can invoke that service.
For CognitoIdentityProvider, try using this policy for your IAM role:
When in doubt which services your IAM role can invoke - check the Access Advisor tab:
I just tested this use case and built a Lambda function that creates a CognitoIdentityProviderClient object and gets users in a specific user pool. I implemented this using the Lambda Java runtime API, but it does not matter what supported Lambda programming language you use. You still need to configure your IAM role in the same way.
This code works perfectly. Here is the Handler class:
public class Handler implements RequestHandler<Map<String,String>, String> {
#Override
public String handleRequest(Map<String,String> event, Context context) {
LambdaLogger logger = context.getLogger();
String pool = event.get("Pool");
logger.log("pool: " + pool);
CognitoInfo cog = new CognitoInfo();
String xml = cog.getUsers(pool);
logger.log("XML: " + xml);
return xml;
}
}
Here is a method named getUsers located in the CognitoInfo class that invokes the AWS Service:
public String getUsers( String userPoolId) {
CognitoIdentityProviderClient cognitoclient = CognitoIdentityProviderClient.builder()
.region(Region.US_EAST_1)
.build();
try {
ArrayList<String> userList = new ArrayList();
// List all users
ListUsersRequest usersRequest = ListUsersRequest.builder()
.userPoolId(userPoolId)
.build();
ListUsersResponse response = cognitoclient.listUsers(usersRequest);
for(UserType user : response.users()) {
userList.add(user.username());
}
return convertToString(toXml(userList));
} catch (CognitoIdentityProviderException e){
System.err.println(e.awsErrorDetails().errorMessage());
System.exit(1);
}
return "";
}
The Lambda function is configured to use an IAM role named lambda-support2 that has the AmazonCognitoPowerUser policy.
This Lambda function successfully retrieves the users in a specific user pool:
Make sure that all your Lambda functions have the proper IAM role configured.

aws-cdk LambdaRestApi: The final policy size is bigger than the limit

Hi i have been trying many possibilities, but now i would need some help.
I am using aws-cdk to create architecture by code and so far things have going well. Now i am running into this issue:
The final policy size is bigger than the limit (20480)
In understand what it means, but i have no idea how to solve it.
I am creating a lambdafunction to handle all requests:
const router = new lambda.Function(this, apiName + '-handler-temp', {
runtime: LambdaRuntime, // execution environment
code: lambda.Code.fromAsset('bin/lambda'), // code loaded from "lambda" directory
handler: 'index.handler', // file is "index", function is "handler"
vpc: vpc,
environment: {
DB_HOST: props?.rdsEndpoint as string,
DB_USER: props?.rdsDbUser as string,
DB_PASS: props?.rdsDBPass as string,
DB_PORT: props?.rdsPort as string,
DB_DIALECT: props?.rdsDbSchema as string,
DB_DATABASE: props?.rdsDBName as string,
},
layers: [layer],
timeout: Duration.seconds(30),
memorySize: 1024,
})
and the LambdaRestApi is defined like this:
const api = new LambdaRestApi(this, apiName, {
handler: router,
proxy: false,
cloudWatchRole: false,
description: 'API for Backend',
deployOptions: {
stageName: 'prod',
},
domainName: domainProperties,
})
I am creating Endpoints where i am using 23 times addMethod.
e.g.
const user = api.root.addResource('user')
user.addMethod(HttpMethod.POST)
user.addMethod(HttpMethod.GET)
user.addMethod(HttpMethod.PATCH)
since only one lambda is used to be invoked from apigateway, i am curious, how i can get control of only one policy to be used for lambda execution and it is not creating a new one every time.
I also tried to add property
role: role to the lambda function with this role definition:
const role = new Role(this, apiName + 'ApiGWPermissions', {
assumedBy: new ServicePrincipal('apigateway.amazonaws.com'),
})
role.addToPolicy(
new PolicyStatement({
resources: ['*'],
actions: ['lambda:InvokeFunction'],
})
)
but then i am running into different errors.
Has someone solved this riddle?
Cheers
As suggested in the CDK issue which Ian Walters mentioned, stripping the generated method permissions solved this for me. I'm using .Net but I'd expect that the approach should work for all language implementations. This function removes the permissions:
public void StripMethodPermissions(ConstructNode node) {
foreach (var child in node.Children) {
if (child is Amazon.CDK.AWS.APIGateway.Method) {
var method = ((Amazon.CDK.AWS.APIGateway.Method)child);
var permissions = method.Node.Children.Where(c => c is Amazon.CDK.AWS.Lambda.CfnPermission);
foreach (var permission in permissions) {
child.Node.TryRemoveChild(permission.Node.Id);
}
}
if (child.Node.Children.Length > 0) StripMethodPermissions(child.Node);
}
}
I'm using the technique like this:
var api = new RestApi(this, "MyRestApi", new RestApiProps {
RestApiName = "MyRestApiV1"
});
var handlerLambda = new Function(this, "RequestHandler", new FunctionProps {
Runtime = Runtime.DOTNET_CORE_3_1,
...
});
// Add resources and methods which use the handlerLambda here
// Remove all generated permissions
StripMethodPermissions(api.Root.Node);
// Add a single invoke permission for the lambda
handlerLambda.GrantInvoke(new ServicePrincipal("apigateway.amazonaws.com"));
Thanks to nija-at for showing the way
#Elliveny has the correct answer. Here is a code snitbit for Python which does the same thing (as I cannot post formatted code in comments):
from aws_cdk import (
aws_lambda as _lambda,
aws_events as events,
aws_iam as iam,
core,
)
for child in self.node.children:
if isinstance(child, events.Rule):
for eventChild in child.node.children:
if isinstance(eventChild, _lambda.CfnPermission):
child.node.try_remove_child(eventChild.node.id)
Remember that if you do this, you still need to grant invoke on your lambda for the "events.amazonaws.com" ServicePrincipal. Something like:
my_lambda.add_permission(
"RuleInvoke",
principal=iam.ServicePrincipal("events.amazonaws.com"),
action="lambda:InvokeFunction",
source_arn=f"arn:aws:events:{core.Aws.REGION}:{core.Aws.ACCOUNT_ID}:rule/your-rule-name-here*",
)
I hit a similar issue. There is a CDK issue that might help resolve it if addressed,
https://github.com/aws/aws-cdk/issues/9327
Its also worth noting that by default lambda integrations have allowTestInvoke set to true, which pretty much is going to double the policy document size.
I'm not sure if you can alter the integration options for the lambda with LambdaRestApi though, I'm using RestApi directly.
A short term fix might be to use RestApi rather than LambdaRestApi and create the lambda integration directly with the allowTestInvoke option set to false.
The other thing I did that helped was to just create more than one lambda that worked the same way, but got attached to different routes (e.g. same code, permissions etc, just different logical id) to also reduce the policy document size a bit.
I'm a bit pressed for development time hence the work-arounds. Personally, I think the right solution would be to fix it in the CDK and propose a PR such that LambdaRestApi just did what the user would expect, wild-card permission for the lambda for all
You can increase the memory size of lambda by doing this
Type: AWS::Serverless::Function
Properties:
CodeUri: src/promoCodes/
Role: !GetAtt FunctionRole.Arn
Handler: promoCodesListCsvPDF.promoCodesListCsvPDF
Policies:
- AWSLambdaExecute # Managed Policy
- AWSLambdaBasicExecutionRole # Managed Policy
MemorySize: 512
Layers:
- !Ref NodeDependenciesLayer
Events:
promoCodesListCsvPDFEvent:
Type: Api
Properties:
Path: /api/promo-codes/csv-pdf
Method: POST