AWS Secrets Managerでバイナリデータを管理する

AWS Secrets Managerを利用するとシークレットを簡単にローテーション、管理、取得することができます。具体的なユースケースとしてはデータベースの認証情報やAPI キーの管理が挙げられますが、AWS Secrets Managerではこの種のテキストデータの他にバイナリデータを保管することもできます。

バイナリのシークレットを扱う身近なユースケースが思いつかなかったのですが、、、興味があったので試してみました。

目次

前提

  • 現時点では、AWSマネージメントコンソールはAWS Secrets Managerへのバイナリデータの保存をサポートしていません。
  • このため、今回はAWS CLIとAWS SDK for Golangを使ってAWS Secrets Managerへのバイナリデータの保存と取得を試しました。
  • AWS Secrets Managerの基本的な利用方法については以下のブログ記事を参照ください。

新サービス「AWS Secrets Manager」をチュートリアル2種(基本設定、RDSローテーション)で基礎から学ぶ

検証環境

  • macOS:Mojave(v10.14.2)
  • AWS CLI:v1.16.90
  • AWS SDK for Golang:v1.16.25

AWS CLIでのバイナリデータの保存・取得

バイナリデータの保存

バイナリデータをファイルに保存し、そのファイルをcreate-secretコマンドの引数に渡します。

we recommend that you store your binary data in a file and then use the appropriate technique for your tool to pass the contents of the file as a parameter.

CreateSecret - AWS Secrets Manager API Referenceより引用

また、リクエストに含めるバイナリデータはBase64でエンコードする必要がありますが、このエンコード処理はAWS CLIが自動的に実行してくれます。単純にバイナリファイルをcreate-secretコマンドの引数に渡せばOKです。

$ aws secretsmanager create-secret --name my-secret-binary-with-cli \
      --description "my secret binary created with the AWS CLI" \
      --kms-key-id "XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" \
      --secret-binary fileb://<binary file>
{
    "ARN": "arn:aws:secretsmanager:ap-northeast-1:XXXXXXXXXXXX:secret:my-secrets-XXXXXX",
    "Name": "my-secret-binary",
    "VersionId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
}

バイナリデータの取得

get-secret-valueでデータを取得します。レスポンスのSecretBinaryにバイナリデータがセットされています。バイナリデータはBase64でエンコードされているので、base64コマンド等でデコードします(お試しということで、以下のコマンド実行例ではバイナリデータをファイルに保存しています)。

$ aws secretsmanager get-secret-value --secret-id my-secret-binary-with-cli \
      | jq -r .SecretBinary \
      | base64 --decode > <binary file>

AWS SDK for Golangでのバイナリデータの保存・取得

バイナリデータの保存

CreateSecretInputSecretBinaryにバイナリデータをセットします。AWS CLI同様、Base64のエンコード処理はAWS SDK側で自動的に行われます。

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/secretsmanager"
)

func main() {
	region := "ap-northeast-1"
	filePath := "./binary_file"
	secretID := "my-secret-binary-with-sdk"
	kmsKeyID := "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"

	file, err := os.Open(filepath.Clean(filePath))
	if err != nil {
		log.Fatal(err.Error())
	}

	defer file.Close()

	data, err := ioutil.ReadAll(file)
	if err != nil {
		log.Fatal(err.Error())
	}

	sess := session.Must(session.NewSession())
	svc := secretsmanager.New(sess, aws.NewConfig().WithRegion(region))
	input := &secretsmanager.CreateSecretInput{
		Description:  aws.String("my secret binary created with the AWS SDK"),
		Name:         aws.String(secretID),
		SecretBinary: []byte(data),
		KmsKeyId:     aws.String(kmsKeyID),
	}

	result, err := svc.CreateSecret(input)
	if err != nil {
		log.Fatal(err.Error())
	}

	fmt.Println(result)
}

バイナリデータの取得

AWS SDK の場合、Base64のデコード処理はAWS SDK側で自動的に行われます(AWS CLIでの実行例と同様に、お試しということでバイナリデータをファイルに保存しています)。

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/secretsmanager"
)

func main() {
    	region := "ap-northeast-1"
	secretName := "my-secret-binary-with-sdk"

	sess := session.Must(session.NewSession())
	svc := secretsmanager.New(sess, aws.NewConfig().WithRegion(region))
	input := &secretsmanager.GetSecretValueInput{
		SecretId: aws.String(secretName),
	}

	result, err := svc.GetSecretValue(input)
	if err != nil {
		log.Println(err.Error())
	}

	file, err := os.Create("binary_file")
	if err != nil {
		log.Println(err.Error())
	}
	defer file.Close()

	_, err = file.Write(result.SecretBinary)
	if err != nil {
		log.Println(err.Error())
	}

	fmt.Println(result)
}

まとめ

ざっと調べた限りではAWS Secrets Managerでバイナリデータを扱うサンプルが見つからなかったので、実際に試してみました。 特にAWS SDKを使う場合はBase64エンコード/デコードが自動的に行われるので、テキストデータのそれとほぼ同様のコードでバイナリデータを扱えることが分かりました。