SORACOM Funnelで使うAWSアクセスキーを自動更新してみる
AWSアクセスキーは、90日のローテーションが推奨されています。AWS Security Hubでもローテーションのルールがあります。
今回は、SORACOMで使っているAWSアクセスキーのローテーションを自動更新するスクリプトを作ってみました。
AWSアクセスキーのローテーション自動化を推奨するものではありません。組織のルール、付与されている権限の内容、扱っている情報、などによって判断してください。
おすすめの方
- AWSアクセスキーをプログラム等でローテーションしたい方
- SORACOM APIを使いたい方
本記事で扱う内容
本記事では、次の内容を扱います。
- 新しいAWSアクセスキーを作成する
- 新しいSORACOM認証情報を作成する
- SORACOM SIMグループの一覧を取得する
- SORACOM Funnelの設定にあるSORACOM認証情報を更新する
なお、次の内容は扱いません。
- 不要になったAWSアクセスキーの削除
- 不要になったSORACOM認証情報の削除
理由は次の2つです。
- AWSアクセスキー更新後、数日ほど様子を見て古いAWSアクセスキーが使われていないことを確認し、古いAWSアクセスキーを削除するため、時系列が違う(数日後に実施するため)
- 不要になったSORACOM認証情報を削除するために、削除する認証情報IDをどこかで保持する仕組みが必要となる
事前準備
まずは、事前準備としてSORACOM FunnelでAWSアクセスキーを使っている状態にします。
- AWS
- IAMユーザを作成する
- アクセスキーを取得する
- AWS IoT Coreエンドポイント取得
- SORACOM
- AWS認証情報を登録する
- SIMグループを作成する
- SORACOM Funnelの設定をする
- SORACOM APIを使う準備
IAMユーザを作成する
SORACOM Funnelでの利用とアクセスキー発行・削除の権限を持つIAMユーザを作成します。
AWSTemplateFormatVersion: 2010-09-09 Description: IAM User for SORACOM Funnel Resources: # SORACOM Funnel用のIAMユーザ SoracomFunnelUser: Type: AWS::IAM::User Properties: UserName: soracom-funnel-sample-user # IAMユーザに付与するIAMポリシー SoracomFunnelUserPolicy: Type: AWS::IAM::Policy Properties: PolicyName: soracom-funnel-user-policy PolicyDocument: Version: "2012-10-17" Statement: # SORACOM Funnel用 - Effect: Allow Action: iot:Publish Resource: !Sub arn:aws:iot:${AWS::Region}:${AWS::AccountId}:topic/soracom/* # AWSアクセスキーの更新用 - Effect: Allow Action: - iam:CreateAccessKey - iam:DeleteAccessKey Resource: !GetAtt SoracomFunnelUser.Arn Users: - !Ref SoracomFunnelUser
デプロイします。
aws cloudformation deploy \ --template-file iam.yaml \ --stack-name SORACOM-Funnel-IAM-User-Sample-Stack \ --capabilities CAPABILITY_NAMED_IAM \ --no-fail-on-empty-changeset
AWSアクセスキーを取得する
aws iam create-access-key \ --user-name soracom-funnel-sample-user
AWS IoT Coreエンドポイント取得
下記コマンドで取得できます。
aws iot describe-endpoint \ --endpoint-type iot:Data-ATS
SORACOMにAWS認証情報を登録する
SORACOM Webコンソールにアクセスし、右上のメニューにある「セキュリティ」を選択します。
続いて、「認証情報ストア」にある「認証情報を登録」を選択します。
種別は「AWS認証情報」を選択し、さきほど取得したアクセスキーを貼り付けて登録します。
AWSアクセスキーの変更は、この認証情報自体を登録し直すので、分かりやすいように認証情報IDに日付を記載しています。
そのためのPrefixとしてaws-soracom-funnel-sample
を利用します。
- aws-soracom-funnel-sample-220810
SIMグループを作成する
適当なSIMグループを作成します。
今回は、「test-1」と「test-2」を使います。
SORACOM Funnelの設定をする
それぞれのSIMグループに対して、SORACOM Funnelの設定を行います。これら2つのSIMグループの「AWS認証情報」をこのあと更新します。(いまは「220810」です)
SORACOM APIを使う準備
- SAMユーザの作成
- SAMユーザのアクセス権限を付与
- SAMユーザの「認証キーID&認証キーシークレット」を取得
上記については、次のブログを参考に行います。
なお、今回のアクセス権限は下記となります。
{ "statements": [ { "api": [ "Credential:createCredential", "Group:listGroups", "Group:putConfigurationParameters" ], "effect": "allow" } ] }
AWSアクセスキーを自動更新する
次の処理を行うスクリプトを作成します。
- 新しいAWSアクセスキーを作成して、SORACOM認証情報を作成して、SORACOM Funnel設定を更新する
- APIトークンの有効期限はデフォルト設定です。
- レートリミットの考慮をしていません。
スクリプトを作成する
import json import boto3 import requests from datetime import datetime from typing import Tuple SORACOM_ENDPOINT = 'https://api.soracom.io/v1' SORACOM_KEY_ID = 'keyId-aaa' SORACOM_SECRET = 'secret-bbb' AWS_IAM_USER_NAME = 'soracom-funnel-sample-user' CREDENTIAL_ID_BASE = 'aws-soracom-funnel-sample' def main() -> None: # 新しいAWSアクセスキーを作成 aws_access_key, aws_secret_access_key = create_aws_access_key() api_key, token = get_token() # SORACOM認証情報を作成 create_credential(api_key, token, aws_access_key, aws_secret_access_key) # SIMグループを取得 groups = get_groups(api_key, token) for item in groups: if 'SoracomFunnel' not in item['configuration']: continue if CREDENTIAL_ID_BASE not in item['configuration']['SoracomFunnel']['credentialsId']: continue # SORACOM Funnelの認証情報を更新する group_id = item['groupId'] print(group_id) put_group_configuration(api_key, token, group_id) def create_aws_access_key() -> Tuple[str, str]: iam = boto3.client('iam') resp = iam.create_access_key( UserName=AWS_IAM_USER_NAME ) return resp['AccessKey']['AccessKeyId'], resp['AccessKey']['SecretAccessKey'] def get_credential_id(): today = datetime.now().strftime('%y%m%d') return f'{CREDENTIAL_ID_BASE}-{today}' def get_token() -> Tuple[str, str]: headers = {'Content-Type': 'application/json'} data = { 'authKeyId': SORACOM_KEY_ID, 'authKey': SORACOM_SECRET, } resp = requests.post(f'{SORACOM_ENDPOINT}/auth', headers=headers, data=json.dumps(data)) d = resp.json() return d['apiKey'], d['token'] def create_credential( api_key: str, token: str, aws_access_key_id: str, aws_secret_access_key: str) -> None: headers = { 'Content-Type': 'application/json', 'X-Soracom-API-Key': api_key, 'X-Soracom-Token': token, } data = { 'type': 'aws-credentials', 'credentials': { 'accessKeyId': aws_access_key_id, 'secretAccessKey': aws_secret_access_key, } } credential_id = get_credential_id() resp = requests.post( f'{SORACOM_ENDPOINT}/credentials/{credential_id}', headers=headers, data=json.dumps(data) ) def get_groups(api_key: str, token: str) -> None: headers = { 'Content-Type': 'application/json', 'X-Soracom-API-Key': api_key, 'X-Soracom-Token': token, } resp = requests.get( f'{SORACOM_ENDPOINT}/groups', headers=headers ) return resp.json() def put_group_configuration(api_key: str, token: str, group_id: str) -> None: headers = { 'Content-Type': 'application/json', 'X-Soracom-API-Key': api_key, 'X-Soracom-Token': token, } data = [ { 'key': 'credentialsId', 'value': get_credential_id(), }, ] resp = requests.put( f'{SORACOM_ENDPOINT}/groups/{group_id}/configuration/SoracomFunnel', headers=headers, data=json.dumps(data) ) if __name__ == '__main__': main()
実行する
python app.py
結果を確認する
新しいAWSアクセスキーが発行された(8/15)
作成日が「220815」のAWSアクセスキーができました。
新しいSORACOM認証情報が登録された(8/15)
登録日時が「220815」のAWS認証情報が登録されました。
SIMグループのSORACOM FunnelのAWS認証情報が更新された(8/15)
それぞれのSIMグループのSORACOM Funnelの設定について、AWS認証情報が「220815」に更新されました。
さいごに
SORACOMで使うAWSアクセスキーを自動更新してみました。今回は手元で実行しましたが、Lambdaを使えば完全自動化もできそうです。 ただし、その場合は、失敗した際の検知&通知の仕組みを忘れずに構築すると良いですね。