redshift-data cliを利用して、sqlを実行する時に、認証方法としてAWS Secrets Managerを利用したいと思います。 Secrets Managerコンソール上で新たなシークレットを作成し、Redshiftのパスワードを自動ローテーションさせる設定までやってみました。

構成

Redshiftクラスターはbastionサーバーを利用し、外部からのアクセスを可能にし、パスワードを自動ローテーションさせるLambdaはNATゲートウェイでなはく、VPCエンドポイントを通すように設定しました。

aws-architecture

シークレット作成と自動ローテーション設定

  • 新たなシークレットを作成します。Redshiftクラスターのユーザー名とパスワードを入力し、対象クラスターを選びます。KMSキーはデフォルトを選びました。
    create-secret1
  • 自動ローテーションを有効にし、ローテーション間隔を入力し、新しいLambda関数を作成します。
    create-secret2

しかし、自動作成されるCloudformationスタック作成に失敗しました。サブネットの数超過による失敗でした。

Properties validation failed for resource SecretsManagerRedshiftRotationSingleUser with message: #/VpcConfig/SubnetIds: expected maximum item count: 16, found: 20

手動で自動ローテーション再設定

失敗したCloudformationスタックを削除し、同じテンプレートでスタックを再度作成します。 パラメーターは失敗したスタックと同じ値を入力し、サブネットはLambdaを作成するサブネットを入力します。

KeyValue
kmsKeyArn-
excludeCharacters:/@"'\
functionNameSecretsManagerRedshiftRotationLambda
endpointhttps://secretsmanager.ap-northeast-1.amazonaws.com
invokingServicePrincipalsecretsmanager.amazonaws.com
vpcSecurityGroupIdssg-0b3xxxcfa
vpcSubnetIdssubnet-0e171673999462f90,subnet-0c21ae038cbe71f48

Cloudformationスタック作成が完了したら、シークレット自動ローテーション設定画面を開き、作成されたLambda関数を選択します。

create-secret3

Lambda実行失敗

Lambda関数に設定したSecurity GroupはRedshiftへ設定されたSecurity Groupと同じです。(自動でLambda関数が作成される場合もRedshiftクラスターと同様なSecurity Groupが設定されます。) Redshiftへ設定されているSecurity GroupはAWS Secrets Managerが作成するLambda関数のInboundアクセスの許可が必要です。

[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へInboundアクセス追加

Redshift Security GroupへSecurity Group自身からRedshiftへアクセスできるようにInboundアクセスを追加

redshift-sg

すぐにシークレットをローテーションさせるを実行

正常にパスワードが変更されました。

[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.

テストQueryを実行

作成されたシークレットを利用して、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
}