AWSアクセスキーを自動的に無効化する方法
はじめに
西藤です。
みなさんはAWSの各種サービスを使った開発を行う際、AWSの各種操作の権限を取得するための「アクセスキー」の取り扱いはどのようにしていますか?
アクセスキー(とシークレットキー)は漏洩した場合、不正にAWSリソースを作成・利用されてしまう恐れなどがあります。
そのため、不正利用を防ぐために
- アクセスキーを用いず、「ロール」ベースでの権限付与
- アクセスキー自体に付与する権限を必要最低限のものにする
などの対策が考えられます。
しかし、「個人的に何かAWSを使って検証したい」というようなときには「権限を最小限に絞って….」などの調整は後回しにしてしまいがちです。
「AWSを使った検証」が目的なのですから、「権限の調整」に時間を取られたくはありませんよね。
とはいえ、不正利用されないためのなんらかの措置は講じておきたいもの….
今回はそんな開発者の方に使っていただきたい自動化設定の実装例を紹介いたします。
実装想定
今回は次のような場面を想定しています。
- IAMユーザーを発行しており、それに紐づくアクセスキーを使用している
仮にこのIAMユーザー名を access-key-user
としましょう。
AWSマネジメントコンソールの画面で言うとこんな感じでしょうか
そして、今回は
- 日本時刻0:00になったら
access-key-user
のアクセスキーを無効化する。
という仕組みを実装します。
(”Serverless Framework”を使用しますが、デプロイ自体の解説は割愛いたします。)
実装用のコード内容
Lambda関数
Lambda関数はPythonで実装して、コードは次の通りです。
handler.py
import json
import os
import boto3
def deactivate_access_key(access_key):
responce = access_key.deactivate()
print(responce)
HTTPStatusCode = responce['ResponseMetadata']['HTTPStatusCode']
print("HTTPStatusCode:")
print(HTTPStatusCode)
accessKeyId = access_key.access_key_id
print(accessKeyId + " is deactivated.")
return
def main(event, context):
# 環境変数から取得
targetAccessKeyUserName = os.environ['TARGET_ACCESS_KEY_USER_NAME']
targetAccessKeyId = os.environ['TARGET_ACCESS_KEY_ID']
# IAMのリソース作成
iamResource = boto3.resource('iam')
access_key = iamResource.AccessKey(targetAccessKeyUserName, targetAccessKeyId)
# アクセスキーの無効化
deactivate_access_key(access_key)
return
コード内には環境変数が2つありますが、それぞれ
TARGET_ACCESS_KEY_USER_NAME
は無効化を行いたいアクセスキーが紐づくIAMユーザー名(今回の例では access-key-user
)
TARGET_ACCESS_KEY_ID
は無効化を行いたいアクセスキー(AKIAIOSFODNN7EXAMPLE
のような英数字で表される)
を適用します。
※もし、Serverless Frameworkを使わない場合はLambdaの環境変数設定にて記載してください。
そして、このLambda関数が実行されるとターゲットとなるアクセスキーが無効化されます。
Serverless Frameworkの実装準備
次に、上記のLambda関数を毎日0:00に自動実行する設定を行なっていきます。
Serverless Frameworkでの実装で使う.env
ファイルとserverless.yml
ファイルは次のようになります。
.env
AWS_ACCESS_KEY_ID=<Serverless Frameworkでデプロイを行う用のアクセスキー>
AWS_SECRET_ACCESS_KEY=<Serverless Frameworkでデプロイを行う用のシークレットキー>
TARGET_ACCESS_KEY_USER_NAME=access-key-user
TARGET_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
serverless.yml
service: deactivate-access-key
plugins:
- serverless-dotenv-plugin
- serverless-prune-plugin
custom:
dotenv:
include:
- TARGET_ACCESS_KEY_USER_NAME
- TARGET_ACCESS_KEY_ID
prune:
automatic: true
number: 1
package:
exclude:
- ./**
include:
- ./handler.py
provider:
name: aws
runtime: python3.8
region: ap-northeast-1
stage: dev
memorySize: 128
iamRoleStatements:
- Effect: Allow
Action:
- "iam:UpdateAccessKey"
Resource:
- "*"
functions:
deactivate-access-key:
description: アクセスキーの無効化
name: deactivate-access-key
handler: handler.main
events:
- schedule:
name: deactivate-access-key
description: JST 0:00にアクセスキーを無効化する
rate: cron(00 15 * * ? *)
注目していただきたいのは、最後、数行分の部分です。
cronでの指定がありますがこれにより上記のLambda関数が毎日JST 0:00に実行されるようにCloudWatch Eventsルールの設定が付きますので、
「夜になったらAWSアクセスキーを自動的に無効化」が実現します。
あと、Dockerベースでデプロイできるようにしましょう。
Dockerfile
とdocker-compose.yml
は次の通りです。
Dockerfile
FROM node:15.3.0-alpine
RUN npm update -g
# install serverless framework
RUN npm install -g serverless
# install serverless plugins
RUN npm i -D serverless-dotenv-plugin
RUN npm install --save-dev serverless-prune-plugin
# change work directory
WORKDIR /app
COPY . /app/
docker-compose.yml
version: "3.8"
services:
serverless:
build:
context: .
volumes:
- .:/app
env_file:
- .env
実装結果
以上を踏まえて、デプロイすると次のようになります。
Lambda関数
CloudWatch Eventsルール
JST 0:00になるとアクセスキーを無効化するLambda関数が実行される。と言う形です。
そして、この設定を終えて、Lambda実行ログを見ますと
と言うようにアクセスキーの無効化が実行された旨表示されており、アクセスキーのあるIAMユーザーの情報を見にいくと
ちゃんと、アクセスキーが無効になっています。
まとめ
以上でAWSアクセスキーを自動的に無効化する実装の完了です。
このようにしておけば、仮にAWSアクセスキーに強力な権限を付与したまま残してしまっていても、少なくとも毎日0:00になったらアクセスキー自体が無効化されるので、「強い権限付与した状態を忘れたまま放置してしまっていた」と言うような場面は回避できます。
本来は最小権限の原則に則って必要な権限を必要なだけ付与する、アクセスキーの漏洩に注意しキー自体も定期的なローテーションを行うなど、IAMのベストプラクティスに沿った運用を行うことが大原則ではありますが、安全にアクセスキーを使うための1つのアイディアとして参考になれば幸いです。