TOP>コラム一覧>AWS のセキュリティ強化④ ~ Secret Manager編 ~

AWS のセキュリティ強化④ ~ Secret Manager編 ~

はじめに

こんにちは、高橋です。
久しぶりの「簡単にできるAWSのセキュリティ強化」シリーズとして、AWS Secrets Managerについてご紹介したいと思います。なぜこの機能かと言われれば、私が今年AWS Certified Solutions Architect – ProfessionalとAWS Certified Security - Specialty の2つの認定資格を受験したのですが、その両方で重要なサービスとして出てきため、その勉強結果と有用性を皆様に共有したかったからです。

1.AWS Secrets Managerとは?

AWS Secrets Managerはパスワード等の機密性の高い情報(以下シークレット)を安全に保管、共有することができる機能です。例えばデータベース認証のパスワードは、複数の関係者やアプリケーションが共通で使用するケースがあると思いますが、これまでこういった場合はデータベースにアクセスするサーバのローカルにファイルに保存して共有したり、アプリケーション内にパスワードを書きこんでいたと思いますが、そうすると本来閲覧不要な人にまでアクセス可能だったり、GitHubでソースの保存ができなかったり、変更したくてもデータベースにアクセスする全てのユーザ、アプリケーションで保存しているパスワードを変更しなければならないため、ついつい初期からパスワードが変更できず、セキュリティ的に高いリスクを負うことになってしまっていました。AWS Secrets Managerを使用すれば、安全にパスワードの保存・共有することは勿論、パスワードが外部で保存されているため、定期的な変更を行うことができるようなります。また、いつ、誰がパスワードを使用したかも分かるため、気密性の高い情報の管理にはうってつけのサービスと言えます。

2.AWS Secret Managerの利用料金

AWS Secret Manageは保存したシークレットの数と呼び出された回数に対して課金され、1シークレットごとに$0.04、10000APIコール(呼び出し)毎に$0.05(ともに2024/2時点の料金)と非常に安価に利用することが可能です。

3.アクセス方法

AWS Secret Managerに保存されているシークレットには以下の方法でアクセスすることが可能です。

利用者 アクセス方法
AWSコンソール
コマンドライン AWS CLI
AWS SDK Java, Python, .NET, Go, Java script, PHP, Ruby, C#
AWSサービス
(直接的にアクセス)
AWS Batch, AWS CloudFormation, Amazon ECS, Amazon EKS, AWS IoT Greengrass, AWS Lambda

具体的な利用イメージは主に以下の様にプログラムがAWS SDKを用いてAWS Secret Managerから認証情報を取得して、取得した情報を元にデータベース等にアクセスする形となります。

4.シークレットの保護

AWS Secret Manager内のシークレットを保護する機能としては主に以下のものがあります。

  1. ① アクセス制御
  2. ② 暗号化
  3. ③ ローテーション
  4. ④ レプリケーション

アクセス制御は他のサービスと同様にIAMで行われます。実際にプログラムからアクセスする場合はIAMロールを作成しておき、STSで一時認証を引き受けてアクセスするのが通常のやり方になります。
次にシークレットをAWS Secret Managerに保存する際にAWS KMSで暗号化することができます。これによりAWS KMSにアクセス権のないユーザからシークレットを保護することができます。また、この観点から利用者を限定するためにシークレット単位でKMS内の暗号化キーを分けることが推奨いたします。
また、作成時にスケジュールを組んでAmazon RDSやRedShiftの認証情報を変更することもできるため、定期的にパスワードを変更することでデータベースのセキュリティを向上されることもできます。
さらに、作成時にシークレットのレプリケーション設定を行うことができるため、データベースのレプリケーションとセットで設定しておくことで、災害対策にも対応することができます。

5.シークレットの作成から使用まで

ここからはAWS Secret Managerでシークレットの保管から実際の利用まで見てみたいと思います。
AWS Secret Managerのコンソール画面で「新しいシークレットを保存する」をクリックすると下記の設定画面が開きます。
最初の画面ではどんなタイプのもののシークレットかとその値、暗号化する場合の暗号化キーを選択します。ここではRDSの認証情報を設定していますが、この場合ログインユーザを入力し、対象のDBインスタンスを選択することになります。

次のページではこのシークレットの名前と他アカウントからのアクセス許可、レプリケーション設定を行えます。レプリケーションは任意のリージョンを指定することができます。

次に自動ローテーションの設定を行います。自動ローテーションをする場合、その頻度とそれを実行するlambda関数の作成の有無を指定することができます。ローテーション戦略で交代ユーザを選択した場合、ユーザのクローンが作成され、以降2つのユーザのシークレットを交互に変更することによって、1つのユーザ側のシークレットが更新中でももう1つのユーザのシークレットは変更されていないため、Secret Manager内に必ずアクセス可能な認証情報があるため、データベースへの短時間でも接続エラーの許されない環境で有効な方法となります。

最後のページにこのシークレットへアクセスするためのサンプルコードが言語ごとに表示されるので、メモをして使用します。なお、サンプルコードはシークレットの概要画面でも確認することができます。

続いて実際のシークレットが保存され、値が取得できるか試してみます。人が取得するのであれば、コンソールから確認可能で、対象のシークレット画面で「シークレットの値を取得する」をクリックすると、その情報が表示されます。

また、CLIからも簡単に取得して利用することが可能です。

[ec2-user@ip-192-168-0-11 ~]$ aws secretsmanager get-secret-value --secret-id test01
{
    "Name": "test01",
    "VersionId": "5eda0d4e-f781-411f-934c-e72deac20a73",
    "SecretString": "{¥"username¥":¥"dbadmin¥",¥"password¥":¥"test123!¥",¥"engine¥":¥"postgres¥",¥"host¥":¥"testdb-1.cluster-ce5kwjzerty9.ap-northeast-1.rds.amazonaws.com¥",¥"port¥":5432,¥"dbClusterIdentifier¥":¥"testdb-1¥"}",
    "VersionStages": [
        "AWSCURRENT"
    ],
    "CreatedDate": 1708750677.068,
    "ARN": "arn:aws:secretsmanager:ap-northeast-1:111111111111:secret:test01-eyNhMR"
}  

最後にサンプルコードを使ってLambdaからユーザIDとパスワードを取得してみたいと思います。サンプルコードは下記の通りでした。

# Use this code snippet in your app.
# If you need more information about configurations
# or implementing the sample code, visit the AWS docs:
# https://aws.amazon.com/developer/language/python/

import boto3
from botocore.exceptions import ClientError


def get_secret():

  secret_name = "test01"(シークレットの名前)
  region_name = "ap-northeast-1"(シークレットが保存されているリージョン)

  # Create a Secrets Manager client
  session = boto3.session.Session()
  client = session.client(
      service_name='secretsmanager',
      region_name=region_name
  )

  try:
      get_secret_value_response = client.get_secret_value(
          SecretId=secret_name
      )
  except ClientError as e:
      # For a list of exceptions thrown, see
      # https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html
      raise e

  secret = get_secret_value_response['SecretString']

  # Your code goes here.  

実際に値を取り出しているのは「secret = get_secret_value_response['SecretString']」ですが、これはCLIの結果の「SecretString」と同じで、ユーザIDとパスワードを個別に取り出せているわけではありません。また「SecretString」の中身はdict型に見えますが、dict型で扱おうとしても扱えなかったので、一度astモジュールで整形する必要がありました。その結果、実際のコードは下記の様になりました。追加、変更したのは赤字の箇所です。

import boto3
from botocore.exceptions import ClientError
import ast

def lambda_handler(event, context):

  secret_name = "test01"
  region_name = "ap-northeast-1"

  # Create a Secrets Manager client
  session = boto3.session.Session()
  client = session.client(
      service_name='secretsmanager',
      region_name=region_name
  )

  try:
      get_secret_value_response = client.get_secret_value(
          SecretId=secret_name
      )
  except ClientError as e:
      # For a list of exceptions thrown, see
      # https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html
      raise e

  secret = get_secret_value_response['SecretString']

  secret_string = ast.literal_eval(secret)
  name = secret_string['username']
  password = secret_string['password']
  print(name)
  print(password)  

実行してみると下記の様に、ユーザIDとパスワードが無事取得できました。

6.さいごに

今回はAWS環境のセキュリティ強化の第4弾としてAWS Secret Managerについてご紹介しました。これまでのAWS環境自体のセキュリティ強化とは異なり、所謂パスワード管理の強化の内容となりますが、セキュリティ事故の多くは杜撰なパスワード管理に起因しています。AWS Secret Managerを使用すればパスワード管理を一元化し、必要な人・アプリケーションのみに利用を限定することができ、さらには人の手を介さず簡単にパスワードを定期的に更新することも可能となるため、利用しているパスワードのセキュリティを大幅に強化することが可能となります。もしまだ利用していない方がいらっしゃったら、是非AWS Secret Managerの利用を検討してみてください。

CTCは、AWSのビジネス利活用に向けて、お客様のステージに合わせた幅広い構築・運用支援サービスを提供しています。
経験豊富なエンジニアが、ワンストップかつ柔軟にご支援します。
ぜひ、お気軽にお問い合わせください。

お問い合わせ



【著者プロフィール】

高橋 繁義(たかはし しげよし)

伊藤忠テクノソリューションズ株式会社 クラウドアーキテクト

インフラ全般のエンジニアとして20年以上活動し、現在AWS専任の技術担当兼サービス企画担当として活動中
2022年から2年連続でAPN Ambassadorに選任

高橋 繁義(たかはし しげよし)

TOP>コラム一覧>AWS のセキュリティ強化④ ~ Secret Manager編 ~

pagetop