Skip to content
cover-devops

AWS MFA CLI 설정 변경 자동화하기

  • DevOps

📅 October 03, 2019

⏱️3 min read

클라우드 인프라를 관리하는 경우 여러 계정에 걸친 CLI를 사용하는 경우가 빈번합니다. 만일 CLI 사용 시 MFA 인증을 요구하는 계정과 아닌 계정이 혼재되어 있다면 설정이 정말 귀찮아집니다. 이 글에서는 간단한 스크립트를 통해 AWS CLI 설정 변경을 자동화해보려 합니다.


AWS Credential 설정

먼저 사용하는 프로필의 credential 정보를 설정해줍니다. MFA인 프로필과 MFA가 아닌 프로필을 구분하기 위해 아래와 같은 구조로 저장하겠습니다. -default가 붙은 프로필이 MFA를 사용하는 프로필입니다. 스크립트 실행을 통해 autogen 값이 자동생성됩니다.

[test]
aws_access_key_id = mykey
aws_secret_access_key = mykey
 
[dev-default]
aws_access_key_id = mykey
aws_secret_access_key = mykey
 
[prod-default]
aws_access_key_id = mykey
aws_secret_access_key = mykey
 
[dev]
aws_arn_mfa = arn:aws:iam::myaccount:mfa/myaccount
aws_access_key_id = autogen
aws_secret_access_key = autogen
aws_session_token = autogen
 
[prod]
aws_arn_mfa = arn:aws:iam::myaccount:mfa/myaccount
aws_access_key_id = autogen
aws_secret_access_key = autogen
aws_session_token = autogen
  • aws_arn_mfa : MFA 에 대한 ARN 값 입니다. 콘솔의 security credentials 메뉴에서 확인하실 수 있습니다.
  • aws_session_token: MFA 인증을 거치게 되면 생성되는 STS 토큰 값 입니다. 스크립트를 통해 자동생성 됩니다.

MFA 설정 스크립트

다음으로 아래의 스크립트를 각 awsp.sh, mfa.py 이름으로 ~/.aws/ 경로에 추가해줍니다. 이후에 ~/.zshrc 또는 ~/.bashrc 경로에 source ~/.aws/awsp.sh를 추가해줍니다.

#! /bin/bash

setProfile() {
  export AWS_PROFILE=$1
  export AWS_DEFAULT_PROFILE=$1

  python ~/.aws/mfa.py --profile $1 $2
}
alias awsp=setProfile

import os
import json
import sys
import argparse
import subprocess
import configparser

parser = argparse.ArgumentParser(description='Update your AWS CLI Token')
parser.add_argument('token', help='token from your MFA device')
parser.add_argument('--profile', help='aws profile to store the session token', default=os.getenv('AWS_PROFILE'))
parser.add_argument('--arn', help='AWS ARN from the IAM console (Security credentials -> Assigned MFA device). This is saved to your .aws/credentials file')
parser.add_argument('--credential-path', help='path to the aws credentials file', default=os.path.expanduser('~/.aws/credentials'))

args = parser.parse_args()

if args.profile is None:
    parser.error('Expecting --profile or profile set in environment AWS_PROFILE. e.g. "stage"')

config = configparser.ConfigParser()
config.read(args.credential_path)

if args.profile not in config.sections():
    parser.error('Invalid profile. Section not found in ~/.aws/credentails')

if args.arn is None:
    if 'aws_arn_mfa' not in config[args.profile]:
        sys.exit(0)
# parser.error('ARN is not provided. Specify via --arn')

    args.arn = config[args.profile]['aws_arn_mfa']
else:
    # Update the arn with user supplied one
    config[args.profile]['aws_arn_mfa'] = args.arn

# Generate the session token from the profile
result = subprocess.run(['aws', 'sts', 'get-session-token', '--profile', args.profile + '-default', '--serial-number', args.arn, '--token-code', args.token], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if result.returncode != 0:
    parser.error(result.stderr.decode('utf-8').strip('\n'))

credentials = json.loads(result.stdout.decode('utf-8'))['Credentials']

config[args.profile]['aws_access_key_id'] = credentials['AccessKeyId']
config[args.profile]['aws_secret_access_key'] = credentials['SecretAccessKey']
config[args.profile]['aws_session_token'] = credentials['SessionToken']

# Save the changes back to the file
with open(args.credential_path, 'w') as configFile:
    config.write(configFile)

print('Saved {} credentials to {}'.format(args.profile, args.credential_path))

이제 awsp [프로필명] [mfa code]과 같은 명령어로 사용하실 수 있습니다. 예를 들어 dev 프로필의 경우 awsp dev 012345와 같이 실행합니다. MFA 조건이 없는 프로필의 경우 awsp test 0과 같이 실행하시면 됩니다.


← PrevNext →
  • Powered by Contentful
  • COPYRIGHT © 2020 by @swalloow