redshift-data cli를 이용해서 sql을 실행할 때 인증방식으로 AWS Secrets Manager를 사용하려고 합니다. Secrets Manager콘솔에서 새 시크릿을 만들고 Redshift의 패스워드를 자동으로 교체하는 설정까지 해보았습니다.
구성
Redshift클러스터는 배스천 서버를 이용해서 외부에서도 접속할 수 있도록 했고, 패스워드를 자동교체하는 람다는 NAT게이트웨이가 아닌 VPC엔드포인트를 통하도록 설정했습니다.

시크릿 생성과 자동교체 설정
- 새 시크릿을 생성합니다. Redshift 클러스터의 유저명과 패스워드를 입력하고 클러스터를 선택 해 줍니다. KMS키는 디폴트 키를 선택했습니다.
- 자동교체를 활성화 하고 교체 간격을 선택 해 줍니다. 새 람다함수를 생성합니다.
자동으로 생성되는 Cloudformation 스택생성에 실패했습니다. 서브넷 갯수 초과로 인한 실패입니다.
Properties validation failed for resource SecretsManagerRedshiftRotationSingleUser with message: #/VpcConfig/SubnetIds: expected maximum item count: 16, found: 20
수동으로 자동교체 재설정
실패 한 Cloudformation 스택을 삭제하고 동일한 템플릿으로 스택을 생성합니다. 파라미터는 실패한 스택과 동일하게 입력하고 서브넷은 람다를 작성 할 서브넷을 입력 해 줍니다.
Key | Value |
---|---|
kmsKeyArn | - |
excludeCharacters | :/@"'\ |
functionName | SecretsManagerRedshiftRotationLambda |
endpoint | https://secretsmanager.ap-northeast-1.amazonaws.com |
invokingServicePrincipal | secretsmanager.amazonaws.com |
vpcSecurityGroupIds | sg-0b3xxxcfa |
vpcSubnetIds | subnet-0e171673999462f90,subnet-0c21ae038cbe71f48 |
Cloudformation 스택생성이 완료되면 시크릿 자동 교체 설정화면을 열고 작성된 람다함수를 선택 해 줍니다.
람다 실행 실패
람다에 설정한 Security Group은 Redshift에 연결된 Security Group과 동일한데 (자동으로 람다 생성시에도 선택한 Redshift 클러스터와 동일한 Security Group이 할당됩니다.) Redshift에 연결된 Security Group은 AWS Secrets Manager가 생성하는 Lambda 함수의 인바운드 액세스를 허용해야 합니다.
[ERROR] d352ae22-3b4b-4203-88cf-224160303d56 setSecret: Unable to log into database with previous, current, or pending secret of secret arn arn:aws:secretsmanager:ap-northeast-1:xxxx:secret:dev/Demo/Redshift-8c3rDL
[ERROR] ValueError: Unable to log into database with previous, current, or pending secret of secret arn arn:aws:secretsmanager:ap-northeast-1:xxxx:secret:dev/Demo/Redshift-8c3rDL
Security Group에 인바운드 액세스 추가
Security Group에 자기자신으로부터 Redshift에 access 가능하도록 인바운드 access 설정을 추가
시크릿의 보안 암호 즉시 교체 실행
정상적으로 패스워드가 교체되었습니다.
[INFO] 2021-07-26T00:49:43.267Z 71e0d30d-8017-402f-b4a0-2305320e8d86 createSecret: Successfully put secret for ARN arn:aws:secretsmanager:ap-northeast-1:xxxx:secret:dev/Demo/Redshift-8c3rDL and version 1048bb1f-c616-4105-ac27-1508b53f8196.
[INFO] 2021-07-26T00:49:44.137Z e4b636ee-6db7-4657-829f-c6585c1a67c1 setSecret: Successfully set password for user awsuser in Redshift DB for secret arn arn:aws:secretsmanager:ap-northeast-1:xxxx:secret:dev/Demo/Redshift-8c3rDL.
[INFO] 2021-07-26T00:49:44.476Z 44366043-316b-4494-8a30-67d3bad38883 testSecret: Successfully signed into Redshift DB with AWSPENDING secret in arn:aws:secretsmanager:ap-northeast-1:xxxx:secret:dev/Demo/Redshift-8c3rDL.
[INFO] 2021-07-26T00:49:44.798Z 8253ea08-1bb1-4474-a669-699a51dfc795 finishSecret: Successfully set AWSCURRENT stage to version 1048bb1f-c616-4105-ac27-1508b53f8196 for secret arn:aws:secretsmanager:ap-northeast-1:xxxx:secret:dev/Demo/Redshift-8c3rDL.
테스트 쿼리 실행
작성한 시크릿을 이용해서 sql을 실행 해 줍니다.
테스트용 유저에는 AmazonRedshiftDataFullAccess
권한을 추가했습니다.
aws redshift-data execute-statement \
--database dev \
--cluster-identifier test-redshift-cluster \
--secret-arn arn:aws:secretsmanager:ap-northeast-1:xxxx:secret:dev/Demo/Redshift-8c3rDL \
--region ap-northeast-1 \
--sql "select * from sales limit 5;" \
--profile redshift
* 결과
{
"ClusterIdentifier": "test-redshift-cluster",
"CreatedAt": "2021-07-26T09:56:18.888000+09:00",
"Database": "dev",
"Id": "61c1630b-9676-4ed4-bb25-d73f92efee76",
"SecretArn": "arn:aws:secretsmanager:ap-northeast-1:xxxx:secret:dev/Demo/Redshift-8c3rDL"
}
sql결과 확인
aws redshift-data get-statement-result \
--id 61c1630b-9676-4ed4-bb25-d73f92efee76 \
--region ap-northeast-1 \
--profile redshift
* 결과
{
"Records": [
[
{
"longValue": 33095
},
{
"longValue": 36572
},
{
"longValue": 30047
},
{
"longValue": 660
},
{
"longValue": 2903
},
{
"longValue": 1827
},
{
"longValue": 2
},
{
"stringValue": "234.00"
},
{
"stringValue": "35.10"
},
{
"stringValue": "2008-01-01 09:41:06"
}
]
... 생략
],
"ColumnMetadata": [
{
"isCaseSensitive": false,
"isCurrency": false,
"isSigned": true,
"label": "salesid",
"length": 0,
"name": "salesid",
"nullable": 0,
"precision": 10,
"scale": 0,
"schemaName": "public",
"tableName": "sales",
"typeName": "int4"
}
... 생략
],
"TotalNumRows": 5
}