aws-samples / aws-secrets-manager-rotation-lambdas Goto Github PK
View Code? Open in Web Editor NEWContains Lambda functions to be used for automatic rotation of secrets stored in AWS Secrets Manager
License: MIT No Attribution
Contains Lambda functions to be used for automatic rotation of secrets stored in AWS Secrets Manager
License: MIT No Attribution
When requiring TLS connections to a DB instance there is a certificate available to verify the connection.
Asking for the ability to configure the Lambda to specify the regional certificate when creating the rotation Lambda from the serverless repo.
Example of the the parameters used when establishing the connection can be found here.
Here is the yaml configuration for deploying the AWS::Serverless::Application
RDSSecretRotationService:
Type: "AWS::Serverless::Application"
Properties:
Location:
ApplicationId: arn:aws:serverlessrepo:region:id:applications/SecretsManagerRDSPostgreSQLRotationSingleUser
SemanticVersion: 1.0.117
Parameters:
endpoint: !Sub "https://secretsmanager.${AWS::Region}.${AWS::URLSuffix}"
functionName:
Fn::Join:
- ""
- - Fn::ImportValue: !Sub ${ClusterImportPrefix}-ClusterResolvingName
- "-rds-rotation-lambda"
vpcSubnetIds:
Fn::ImportValue: !Sub ${VPCImportPrefix}-PrivateSubnets
vpcSecurityGroupIds: !Ref RDSSecurityGroup
where can the documentation for the parameter list supported by this AWS resource (AWS::serverless::application)
I tried to add both
Runtime: "python3.7"
runtime: "python3.7"
failed to do so
I ran into a problem deploying this using KMS-CMKs using a single pass because I can't create the IAM Role first so the CMK policy can include its ARN for access. This can, of course, be solved by changing the CMK policy after the fact but that is non-trivial to implement in common tools like CloudFormation or Terraform.
It seems like this could most easily be implemented by allowing an IAM role to be provided as an input so the CMK key policy could be configured first and then all of the same IAM policies could be attached by this stack.
MultiUser templates are creating cloned users and replicating grants.
Although this is convenient, we have to maintain the different grant methods in the different db engines templates with fair amount of complexity. When complexity deepens, we introduce risks of points of failures.
Since the <db_user> needs to be pre-created with the necessary grants, why not <db_user>_clone?
So did the following to prepare the depedency package
pip install --target ./package pg
pip install --target ./package pgdb
cd package
zip -r ../deployment.zip .
[ERROR] Runtime.UserCodeSyntaxError: Syntax error in module 'lambda_function': invalid syntax (init.py, line 3)
Traceback (most recent call last):
File "/var/task/pg/init.py" Line 3
async,
Tried with python 3.6, 3.7 & 3.8; no luck; googling does not seem to help much either...
Hello,
Multi user strategies require access to a master secret.
When deploying the strategy with the AWS Serverless Repository the only way I see to allow this is to add in my CF template a resource policy on the master secret allowing the role created by the Serverless Application to call GetSecretValue
. Since this role is not outputed, I cannot find a way to achieve this.
From: https://forums.aws.amazon.com/thread.jspa?threadID=322708
Hi,
I'm trying to setup secretsmanager rotation and found these lambda function examples here... but can't get these to work.
It seems like the tokens received by Lambda (event) don't match the tokens/VersionStages fetched when calling seceretsmanager API (describe_secret), so the function fails raising an exception.
Please see the Lambda output below:
START RequestId: 869a3608-f930-43dd-9337-b71edc57f134 Version: $LATEST
EVENT_DATA: {'ClientRequestToken': 'AF585B8F-AA06-4EAB-8827-EFF43E6FD896', 'SecretId': 'arn:aws:secretsmanager:eu-west-1:passwd-WqYjGj', 'Step': 'createSecret'}
DESC_SECRET {'ARN': 'arn:aws:secretsmanager:eu-west-1:passwd-WqYjGj', 'Name': 'passwd', 'KmsKeyId': '41b10ffe-b86d-412f-8bb5-d63ba990e585', 'RotationEnabled': True, 'RotationLambdaARN': 'arn:aws:lambda:eu-west-1:XXX:function:rotate-secrets', 'RotationRules': {'AutomaticallyAfterDays': 90}, 'LastChangedDate': datetime.datetime(2019, 8, 5, 16, 18, 40, 344000, tzinfo=tzlocal()), 'Tags': [{'Key': 'Environment', 'Value': 'uat'}, {'Key': 'Owner', 'Value': 'terraformer'}, {'Key': 'Terraform', 'Value': 'true'}], 'VersionIdsToStages': {'AF585B8F-AA06-4EAB-8827-EFF43E6FD896': ['AWSPENDING']}, 'ResponseMetadata': {'RequestId': '75613522-63e9-42c3-999c-ba1d728f08e8', 'HTTPStatusCode': 200, 'HTTPHeaders': {'date': 'Mon, 05 Aug 2019 16:18:41 GMT', 'content-type': 'application/x-amz-json-1.1', 'content-length': '583', 'connection': 'keep-alive', 'x-amzn-requestid': '75613522-63e9-42c3-999c-ba1d728f08e8'}, 'RetryAttempts': 0}}
[ERROR] ResourceNotFoundException: An error occurred (ResourceNotFoundException) when calling the GetSecretValue operation: Secrets Manager can’t find the specified secret value for staging label: AWSCURRENT
Traceback (most recent call last):
File "/var/task/lambda_function.py", line 61, in lambda_handler
create_secret(service_client, arn, token)
File "/var/task/lambda_function.py", line 88, in create_secret
service_client.get_secret_value(SecretId=arn, VersionStage="AWSCURRENT")
File "/var/runtime/botocore/client.py", line 320, in _api_call
return self._make_api_call(operation_name, kwargs)
File "/var/runtime/botocore/client.py", line 623, in _make_api_call
raise error_class(parsed_response, operation_name)
END RequestId: 869a3608-f930-43dd-9337-b71edc57f134
REPORT RequestId: 869a3608-f930-43dd-9337-b71edc57f134 Duration: 1039.40 ms Billed Duration: 1100 ms Memory Size: 128 MB Max Memory Used: 71 MB
Can you please advise on how to solve that issue ?
Hello.
We are planning to have Postgres roles that have the reader endpoint in the secret host attribute to enforce use of the Aurora reader endpoint without the application having to worry about changing endpoint URL's. Am I right in thinking that rotation will fail due to the reader endpoint being passed to the rotation Lambda?
If so, what is the solution? Customize the Lambda? Change our approach?
Thanks.
Almost all of their lambdas dont take into account the password length parameter.
Only four of lambdas use password length as argument, but it's hardcoded.
Can we pass password length as env variable, as it's done with excluded character?
Hi, I have had the following error takes 1 positional argument but 2 positional arguments (and 5 keyword-only arguments) were given
I have addressed the issue by adding host as a keyword argument to connection string on line 269.
Function: get_connection
Line: 269
Fix: conn = pymysql.connect(host=secret_dict['host'], user=secret_dict['username'], passwd=secret_dict['password'], port=port, db=dbname, connect_timeout=5)
Hi all,
I am using the below code in node JS to rotate the secret but i am facing an error. I am mentioning the code and the error below.I am not using client request token assuming it's an optional parameter. Please let me know where i am going wrong.
Code:
// Ensure you have installed these two packages
const AWS = require('aws-sdk');
const ServiceURL = "https://vpce-0ee-s82syo9o.secretsmanager.us-east-1.vpce.amazonaws.com/";
const endpoint = ServiceURL;
const region = "us-east-1";
const secretName = "1033-Rotation-Lambda";
const rotationInterval = 30;
const rotationLambdaARN = "arn:aws:lambda:us-east-36390381:function:1033_PasswordRotation";
const secretsManager = new AWS.SecretsManager({
endpoint: endpoint,
region: region,
});
const params = {
SecretId: secretName,
RotationLamdaARN: rotationLambdaARN,
RotationRules: {
AutomaticallyAfterDays: rotationInterval,
},
};
exports.handler = async (event, context) => {
try {
const response = await secretsManager.rotateSecret(params).promise();
console.log(${secretName} secret rotation complete
);
console.log(response);
} catch (error) {
console.error(An error occurred while attempting to rotate ${secretName} secret
);
console.log(error);
}
};
// SAMPLE ENVIRONMENT/CONFIG FILES- Use what fits your current app setup
/**
/**
Error:
Response:
{
"errorType": "Runtime.UserCodeSyntaxError",
"errorMessage": "SyntaxError: Invalid or unexpected token",
"trace": [
"Runtime.UserCodeSyntaxError: SyntaxError: Invalid or unexpected token",
" at _loadUserApp (/var/runtime/UserFunction.js:98:13)",
" at Object.module.exports.load (/var/runtime/UserFunction.js:140:17)",
" at Object. (/var/runtime/index.js:45:30)",
" at Module._compile (internal/modules/cjs/loader.js:778:30)",
" at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)",
" at Module.load (internal/modules/cjs/loader.js:653:32)",
" at tryModuleLoad (internal/modules/cjs/loader.js:593:12)",
" at Function.Module._load (internal/modules/cjs/loader.js:585:3)",
" at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)",
" at startup (internal/bootstrap/node.js:283:19)"
]
}
Request ID:
"6705fb8f-b909-4381-b8c3-cfbffa6f7d18"
Function Logs:
START RequestId: 6705fb8f-b909-4381-b8c3-cfbffa6f7d18 Version: $LATEST
2019-11-11T10:17:04.575Z undefined ERROR Uncaught Exception {"errorType":"Runtime.UserCodeSyntaxError","errorMessage":"SyntaxError: Invalid or unexpected token","stack":["Runtime.UserCodeSyntaxError: SyntaxError: Invalid or unexpected token"," at _loadUserApp (/var/runtime/UserFunction.js:98:13)"," at Object.module.exports.load (/var/runtime/UserFunction.js:140:17)"," at Object. (/var/runtime/index.js:45:30)"," at Module._compile (internal/modules/cjs/loader.js:778:30)"," at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)"," at Module.load (internal/modules/cjs/loader.js:653:32)"," at tryModuleLoad (internal/modules/cjs/loader.js:593:12)"," at Function.Module._load (internal/modules/cjs/loader.js:585:3)"," at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)"," at startup (internal/bootstrap/node.js:283:19)"]}
END RequestId: 6705fb8f-b909-4381-b8c3-cfbffa6f7d18
REPORT RequestId: 6705fb8f-b909-4381-b8c3-cfbffa6f7d18 Duration: 1903.34 ms Billed Duration: 2000 ms Memory Size: 128 MB Max Memory Used: 24 MB
Unknown application error occurred
Runtime.UserCodeSyntaxError
Using the AWS Serverless Application Repository with both the AWS Serverless Application Module and AWS CloudFormation seems to be missing the Outputs.ApplicationOutputName as specified in the Return values documentation.
I've include the AWS CloudFormation which I used.
rDatabaseCredentialRotationApplication:
Type: AWS::Serverless::Application
Properties:
Location:
ApplicationId: 'arn:aws:serverlessrepo:us-east-1:297356227824:applications/SecretsManagerRDSMySQLRotationSingleUser'
SemanticVersion: 1.0.0
Parameters:
endpoint: !Sub 'https://secretsmanager.${AWS::Region}.amazonaws.com'
The generated nested stack is included below.
AWSTemplateFormatVersion: 2010-09-09
Parameters:
endpoint:
Type: String
Description: The Secrets Manager endpoint to hit
Resources:
SecretsManagerRDSMySQLRotationSingleUser:
Type: 'AWS::Lambda::Function'
Properties:
Code:
S3Bucket: awsserverlessrepo-changesets-CHANGESET-ID-HERE
S3Key: KEY-HERE
Description: >-
Conducts an AWS SecretsManager secret rotation for RDS MySQL using
single user rotation scheme
Tags:
- Value: SAM
Key: 'lambda:createdBy'
Environment:
Variables:
SECRETS_MANAGER_ENDPOINT: !Ref endpoint
AWS_DATA_PATH: models
Handler: lambda_function.lambda_handler
Role: !GetAtt
- SecretsManagerRDSMySQLRotationSingleUserRole
- Arn
Timeout: 30
Runtime: python2.7
SecretsManagerRDSMySQLRotationSingleUserRole:
Type: 'AWS::IAM::Role'
Properties:
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'
Policies:
- PolicyName: SecretsManagerRDSMySQLRotationSingleUserRolePolicy0
PolicyDocument:
Statement:
- Action:
- 'ec2:CreateNetworkInterface'
- 'ec2:DeleteNetworkInterface'
- 'ec2:DescribeNetworkInterfaces'
- 'ec2:DetachNetworkInterface'
Resource: !Sub >-
arn:${AWS::Partition}:ec2:${AWS::Region}:${AWS::AccountId}:network-interface/*
Effect: Allow
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Action:
- 'sts:AssumeRole'
Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Hey, I'm trying to execute the lambda function, but it shows me an error.
ClientError: An error occurred (AccessDeniedException) when calling the GetSecretValue operation: Access to KMS is not allowed
FIle "/../lambda_function.py"
secret = service_client.get_secret_value(SecretId=arn, VersionStage=stage)
I already applied for these permissions
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey"
thanks in advance
Hello,
My team has been working to implement our slightly custom RDS password rotation lambda based on the multi user lambda here:
https://github.com/aws-samples/aws-secrets-manager-rotation-lambdas/blob/master/SecretsManagerRDSPostgreSQLRotationMultiUser/lambda_function.py
We are granting the master user role permissions to our secondary users, and also in between the users (as is done in this repo) and have run into several issues around object ownership (completely breaking) when actually using them with several micro-services.
As I understand this function, it is expecting the multi-user role permissions to look something like this:
master {perms to create objects}
user1 {}
user2 {member of user1}
I think that there is a major flaw in the rotation function as it is setup now. And the issue goes like this:
Assuming user2 is a member of the user1 Role:
We've implemented several fixes around this where we reassign ownership during rotation back to the master user so it can be accessed by both user1 and user2 since they are members of the master role. (I can make a PR to this repo if this is indeed an issue), but this case seems so simple that I'm surprised no-one else is running into issues and wanted to confirm here as well.
Can someone confirm that this is an issue? It basically makes the rotation function unusable as is without heavy customization and/or custom SQL event triggers to reassign ownership. Is there an easy way to fix this, or something that we're missing?
Hi,
According to the official document, MongoDB supports 3.2 or 3.4 for both Single User and Master User.
I would like to use MongoDB 4.0 to build DocumentDB,
So, it would be nice if the lambda to be rotated could also support version 4.0.
Hi everyone,
Can anyone please point me to a document or link where i can find a generic template or code to build solution to rotate secret from lambda function in .net language. i have seen the available one is in python but i am not sure how to begin in .net.
Please provide me your guidance as i am new to both AWS lambdas and secret manager.
Thank you.
Please modify the docstring comment for the test_secret
function.
What is my code supposed to do if the test fails? Do I return False, or throw an exception? If an exception, which exception?
The connection string would be like username/password@host:port/SID
If at the beginning the original password contains @ symbol (say if it's pwd@123), it will never connect to database. Because the connection string becomes: username/pwd@123@host:port/SID, and the host is recognized as 123@host instead of host.
A simple change could avoid this behavior, to use below code:
conn = cx_Oracle.connect(secret_dict['username'], secret_dict['password'], secret_dict['host'] + ':' + port + '/' + secret_dict['dbname'])
Reference:
https://cx-oracle.readthedocs.io/en/latest/api_manual/module.html#
https://cx-oracle.readthedocs.io/en/latest/user_guide/connection_handling.html#connstr
Currently the code (for example SecretsManagerRDSPostgreSQLRotationSingleUser) uses the existing password (in the secret) to authenticate/login and then rotates it (as the documentation explains).
Probably a minor improvement, but does it make sense to use the master secret (if exists in the secret) to rotate the secret? In other words, the function checks the secret and if there's a masterarn
, it uses it to authenticate/login (similar to multi-user flow) and rotates the secret in single-user mode.
One benefit is that the current password doesn't need to be correct. This makes the whole flow in using CDK a little smoother; creating the RDS instance and its additional credentials.
I'm running into an error here:
The conditional doesn't seem to match the error message. Is it supposed to be only validating that the pending username contains the 'clone' suffix?
The message says:
Attempting to modify user %s other than current user or clone %s
But the conditional says:
get_alt_username(current_dict['username']) != pending_dict['username']
I would expect something more like:
if pending_dict['username'] not in [get_alt_username(current_dict['username']), current_dict['username']]
Currently the Application requires passing of the functionName.
All Lambda Functions allow you to not provide that value as to avoid issues with character limits exceeding the 64 character limit.
Not passing errors as:
Parameters: [functionName] must have values
I get this error while executing the lambda for SecretsManagerActiveDirectoryRotationSingleUser
Please suggest
2022-08-01T16:19:08.536+05:30Copy[ERROR] ValueError: execute_kinit_command: kinit failedTraceback (most recent call last): File "/var/task/lambda_function.py", line 136, in lambda_handler create_secret(secrets_manager_client, arn, token, directory_name, current_dict) File "/var/task/lambda_function.py", line 202, in create_secret execute_kinit_command(current_dict, None, directory_name) File "/var/task/lambda_function.py", line 446, in execute_kinit_command raise ValueError("execute_kinit_command: kinit failed") from Exception | [ERROR] ValueError: execute_kinit_command: kinit failed Traceback (most recent call last): File "/var/task/lambda_function.py", line 136, in lambda_handler create_secret(secrets_manager_client, arn, token, directory_name, current_dict) File "/var/task/lambda_function.py", line 202, in create_secret execute_kinit_command(current_dict, None, directory_name) File "/var/task/lambda_function.py", line 446, in execute_kinit_command raise ValueError("execute_kinit_command: kinit failed") from Exception |
---|
Improper SQL query building is present in the several of the password rotation functions. For example, SecretsManagerRDSPostgreSQLRotationSingleUser:
alter_role = "ALTER USER \"%s\"" % pending_dict['username']
cur.execute(alter_role + " WITH PASSWORD %s", (pending_dict['password'],))
pending_dict['username']
should be escaped as an identifier, unfortunately PyGreSQL does not expose this function easily.
I'm wondering if this would work for an Oracle DB running on an ec2 without any code changes.
For SAM functions, you are able to specify a Permissions Boundary to use for the role that gets created automatically by Serverless::Function resources. However, there is no way for us as a consumer of these Serverless Applications to specify that to you.
Could you please add an optional parameter to the Serverless Application that allows us to specify a PermissionsBoundary?
If your App is passed PermissionsBoundary as a parameter by a user, simply pass it down to the Serverless::Function it creates. This should only be a few line change to your template.
We (and others likely) cannot take advantage of your Serverless Apps due being required (by a standard/policy within our organizations) to always specify a PermissionsBoundary on any role we create (or is created for us by things like SAM).
I added password rotation to my database using https://github.com/time-loop/cdk-aurora/blob/main/src/aurora.ts#L284
However, it didn't
Also, what is with the master
stuff? BLM happened years ago. adminSecret
or administratorSecret
if you want to do Microsofty things. Or mainSecret
if you want to follow GitHub's pattern. Or primarySecret
, or controlSecret
. It takes almost no effort at all to not be crass.
Hi,
We tried rotating the secret of non-superusers using master secret. . But It tried connecting with non-superuser only in spite of enabling "use different secret" and it doesn't pick up the master arn. It appears to be the SecretsManagerMongoDBRotationSingleUser doesn't support that
{
"errorMessage": "Syntax error in module 'lambda_function': invalid syntax (init.py, line 3)",
"errorType": "Runtime.UserCodeSyntaxError",
"stackTrace": [
" File "/var/task/pg/init.py" Line 3\n async,\n"
]
}
Hi,
I tried deploying these manually myself and was unable to import "_pg" inside my lambda environment. It appears related to the issue at https://github.com/jkehler/awslambda-psycopg2 where
This is a custom compiled psycopg2 C library for Python. Due to AWS Lambda missing the required PostgreSQL libraries in the AMI image, we needed to compile psycopg2 with the PostgreSQL libpq.so library statically linked libpq library instead of the default dynamic link.
Can the github repository clarify if this is correct and how to build and deploy this code?
I try to use this script but i found the error ORA-28221: REPLACE not specified because i apply oracle user policy and it requires REPLACE syntax
(example: alter user username identified by new password REPLACE old password )
so how to edit the script to support REPLACE in line 216 : "cur.execute("ALTER USER %s IDENTIFIED BY "%s"" % (escaped_username, pending_password))"
i am not the master of programing so please advise
What is this ClientRequestToken in the event_dict of lambda_handler function?
Compiler
Python3.8
Error from cloudwatch
[ERROR] Runtime.UserCodeSyntaxError: Syntax error in module 'lambda_function': invalid syntax (init.py, line 3)
Traceback (most recent call last):
File "/var/task/pg/init.py" Line 3
async,
Reason for error
Async a reserved word from python 3.7
https://docs.python.org/3/whatsnew/3.7.html
This is a very old package - should be replace with something newer which is compatible latest python version.
https://pypi.org/project/pg/#history
Even winding back to python 3.6 results in additional errors (_imaging module).
Could you please clarify the Python Runtime version these lambdas should use. I notice that SecretsManagerRDSPostgreSQLRotationSingleUser — version 1.0.117 is used in the AWS Serverless Application Repository. The template in the repository contains Runtime: python2.7. Can SecretsManagerRDSPostgreSQLRotationSingleUser be safely used with Runtime: python3.7?
We recently had a Postgres secret auto rotate with this code and the new password ended up containing a colon, which is a separator character for lib pg reading the .pgpass file
If the colon character could be added to the ExcludeCharacters attribute when randomly generating a new password then there will be no problem storing the generated secret in .pgpass
I tried using SecretsManagerRDSMySQLRotationSingleUser application to create a lambda function in the AWS console but it looks like this application tries to create a role SecretsManagerRDSMySQLRotationSingleUserRole internally. My company doesn't allow role creation like this. I would like to use this application (to make use of standard rotation code and bundled pymysql etc) but would like to provide my custom role manually.
I did the following command and it only outputs SecretsManagerRDSMySQLRotationSingleUser resource and not the SecretsManagerRDSMySQLRotationSingleUserRole. Also, I don't see any role param for SecretsManagerRDSMySQLRotationSingleUser resource where I can plug-in my custom role.
aws serverlessrepo get-application --application-id arn:aws:serverlessrepo:us-east-1:297356227824:applications/SecretsManagerRDSMySQLRotationSingleUser
I will really appreciate any input on this.
Hey, in the SecretsManagerRDSMySQLRotationSingleUser/lambda_function.py
we expect the field names to be:
{
'engine': <required: must be set to 'mysql'>,
'host': <required: instance host name>,
'username': <required: username>,
'password': <required: password>,
'dbname': <optional: database name>,
'port': <optional: if not specified, default port 3306 will be used>
}
In our case, we were using key names as 'rds.engine' etc for internal purposes.
I would expect the field names to be configurable/dynamic.
Can we look into this?
Thank you for your consideration!
When setting up rotations via the hosted function like below:
from aws_cdk import core, aws_ec2 as ec2
from aws_cdk.aws_rds import DatabaseCluster, DatabaseClusterEngine, InstanceProps, AuroraEngineVersion
from aws_cdk.core import Duration
class Tmp2Stack(core.Stack):
def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
vpc = ec2.Vpc(self, "VPC")
db = DatabaseCluster(
self,
"Database",
engine=DatabaseClusterEngine.aurora(version=AuroraEngineVersion.VER_1_22_2),
instance_props=InstanceProps(vpc=vpc),
)
db.add_rotation_single_user(automatically_after=Duration.days(7))
Then the python 3.7 lambdas are insecure using 2017 version of python cryptography
for grant_type in ['ROLE_GRANT', 'SYSTEM_GRANT', 'OBJECT_GRANT']:
try:
cur.execute("SELECT DBMS_METADATA.GET_GRANTED_DDL('%s', '%s') FROM DUAL" % (grant_type, current_dict['username'].upper()))
results = cur.fetchall()
for row in results:
sql = row[0].read().strip(' \n\t').replace("\"%s\"" % current_dict['username'].upper(), "\"%s\"" % pending_dict['username'])
cur.execute(sql)
except cx_Oracle.DatabaseError:
# If we were unable to find any grants skip this type
pass
Basically this code is to check which privileges the current user has, and then grant them to the pending user. However if the row[0].read returns multiple sqls, it will never commit successfully because cx_Oracle can be used to execute individual statements, one at a time.
In our test situation, DUMMY_USER contains multiple privileges and the sql of SYSTEM_GRANT would become:
GRANT "CONNECT" TO "DUMMY_USER_CLONE"
GRANT "RESOURCE" TO "DUMMY_USER_CLONE"
Then the cur.execute(sql) would raise exception of (We have added a traceback for debugging propose):
Traceback (most recent call last):
File "/var/task/lambda_function.py", line 204, in set_secret
cur.execute(sql)
cx_Oracle.DatabaseError: ORA-00933: SQL command not properly ended
So I suggest to do below modification to make it compatible for above situation.
for grant_type in ['ROLE_GRANT', 'SYSTEM_GRANT', 'OBJECT_GRANT']:
try:
cur.execute("SELECT DBMS_METADATA.GET_GRANTED_DDL('%s', '%s') FROM DUAL" % (grant_type, current_dict['username'].upper()))
results = cur.fetchall()
for row in results:
sqls = row[0].read().strip(' \n\t').replace("\"%s\"" % current_dict['username'].upper(), "\"%s\"" % pending_dict['username'])
for sql in sqls.split('\n'):
cur.execute(sql)
except cx_Oracle.DatabaseError:
# If we were unable to find any grants skip this type
pass
Following lambda does not support aurora engine aurora-postgresql
We've had some issues with some characters that are not excluded on mariadb. We are excluding the following: '%{}`/@"'\'
It would be nice if that was configurable. It would also be nice if we could somehow configure the random password length.
Thanks!
Commit edd300a ("Supports MySQL/Maria grants containing percent symbols.") added a replacement of '%' with '%%' because '%' is an escape character for python format strings. I don't know if something changed in the libraries used or if this is only necessary in certain situations, but it causes problems with the permission grants in the simplest case. This is the specific line that appears to be the problem:
new_grant_escaped = new_grant.replace('%','%%') # % is a special character in Python format strings.
We are using this in a lambda with Python 3.7.
We started with a user 'myuser', with a grant:
GRANT SELECT, INSERT, UPDATE, DELETE, LOCK TABLES, EXECUTE, SHOW VIEW ON %
.* TO 'myuser'@'%'
Each time the key rotation is run, we end up with a grant doubling the wildcard as the grant gets copied back and forth between the base account and the clone account. EG:
GRANT SELECT, INSERT, UPDATE, DELETE, LOCK TABLES, EXECUTE, SHOW VIEW ON %%
.* TO 'myuser_clone'@'%'
After several automatic rotations, we're up to 64 on the main account and 128 on the clone:
GRANT SELECT, INSERT, UPDATE, DELETE, LOCK TABLES, EXECUTE, SHOW VIEW ON %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.* TO 'myuser'@'%'
GRANT SELECT, INSERT, UPDATE, DELETE, LOCK TABLES, EXECUTE, SHOW VIEW ON %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.* TO 'myuser_clone'@'%'
I expect at some point we'll run up against a character limit and rotation will fail.
I can change the lambda locally, but if we ever take a further update from the template, that might get lost. Additionally, I expect other customers are likely to run into this problem if they restrict permissions in this way.
As a workaround, I can grant the privileges separately to each schema in the DB, but that's a little bit painful and error prone if we ever add an additional schema.
is there a nodejs / typescript equivalent of this project ?
Hi folks!
I seem to have come across an issue with the RDS SQL Server rotation lambda. I'm specifically seeing this with "SecretsManagerRDSSQLServerRotationSingleUser".
Steps to reproduce:
Errors:
setSecret: Unable to log into database with previous, current, or pending secret of secret arn <secret arn>
(20002, 'DB-Lib error message 20002, severity 9:\nAdaptive Server connection failed
.I've done some research, and it seems that the version of pymssql
which this lambda uses (pymssql v2.1.1) is not packaged with a version of FreeTDS which supports SSL connections to SQL Server.
I've confirmed that this is my issue as I've tried disabling the rds.force_ssl
paramater (i.e. setting the value to "0") which fixes this issue.
I found a related workaround here for "pymsql" (used in the RDS MySQL rotation lambda): https://aws.amazon.com/premiumsupport/knowledge-center/rotate-secret-db-ssl/ which mentions to update the connection to have an additional parameter ssl={'ca': './rds-combined-ca-bundle.pem'}
, however I do not believe that this is a support parameter in pymssql
.
The Microsoft SQL documentation mentions that the supported python SQL driver is pyodbc
(you can see that here https://docs.microsoft.com/en-us/sql/connect/python/python-driver-for-sql-server?view=sql-server-ver15). I've tested pyodbc
connections to RDS SQL Server and it works well with SSL enabled on the parameter group.
Is there any chance of this issue being resolved by either creating this lambda with a newer version of pymssql
and packaging it with a version of FreeTDS which supports SSL or possibly refactoring to use pyodbc
?
Thanks in advanced and let me know if you have any further questions!
It would be great if the Cloudformation templates for these functions would output the ARN of the role that was created for inclusion in resource policies on the secrets.
Right now the best option I've found is to check userid ~= "*:[rotator function name]"
as in
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Deny",
"Principal": {
"AWS": "*"
},
"Action": [
"secretsmanager:UpdateSecretVersionStage",
"secretsmanager:PutSecretValue",
"secretsmanager:GetSecretValue"
],
"Resource": "*",
"Condition": {
"StringNotLike": {
"aws:userid": [
"AROASECRETADMINROLE:*",
"*:name-of-rotator-function"
]
}
}
}
]
}
Which, for all the protection that provides I just might as well not have a secret policy.
Hi, in CloudWatch getting this error:
Line 357 of SecretsManagerRedshiftRotationMultiUser/lambda_function.py says:
secret = service_client.get_secret_value(SecretId=arn, VersionId=token, VersionStage=stage)
Note that both VersionId
and VersionStage
are specified.
Boto3 documentation for get_secret_value()
says you don't specify both.
What are the semantics when you do specify both?
Why does the provided code disregard the documentation?
VersionId (string) --
Specifies the unique identifier of the version of the secret that you want to retrieve. If you specify this parameter then don't specify VersionStage . If you don't specify either a VersionStage or VersionId then the default is to perform the operation on the version with the VersionStage value of AWSCURRENT .This value is typically a UUID-type value with 32 hexadecimal digits.
VersionStage (string) --
Specifies the secret version that you want to retrieve by the staging label attached to the version.Staging labels are used to keep track of different versions during the rotation process. If you use this parameter then don't specify VersionId . If you don't specify either a VersionStage or VersionId , then the default is to perform the operation on the version with the VersionStage value of AWSCURRENT .
It looks like Python 2.7 is going to stop being supported as of January 1, 2020 based on the information found here:
https://devguide.python.org/#status-of-python-branches
I'm assuming that a lambda runtime environment deprecation will follow soon after.
Last I remember trying to run the RDS single user rotation for PostgreSQL in a Python 3 lambda runtime, it was not compatible. Is there a plan to upgrade these to be Python 3 compatible?
When using AWS CloudFormation with the AWS Serverless Application Module and the AWS Serverless Application Repository, the paramter functionname is not recognized. However, it's listed in the docs for To create a Lambda rotation function by using an AWS Serverless Application Repository template
endpoint – The URL of the service endpoint that you want the rotation function to query. Typically, this is https://secretsmanager.region.amazonaws.com.
functionname – The name of the completed Lambda rotation function that's created by this process.
AWS CloudFormation template is included below.
rDatabaseCredentialRotationApplication:
Type: AWS::Serverless::Application
Properties:
Location:
#https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_available-rotation-templates.html
ApplicationId: 'arn:aws:serverlessrepo:us-east-1:297356227824:applications/SecretsManagerRDSMySQLRotationSingleUser'
SemanticVersion: 1.0.0
Parameters:
endpoint: !Sub 'https://secretsmanager.${AWS::Region}.amazonaws.com'
functionname: 'test-function-name'
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.