AWS SDK 개발 환경 구축Setting Up an AWS SDK Development Environment

AWS CLI와 SDK를 활용한 개발 환경 구축 방법Building a development environment with the AWS CLI and SDK

written by tiaz0128
'AssumeRole'에 대해 더 자세히 알고 싶으시다면, "AWS 임시 자격 증명(AssumeRole)" 글을 확인 해주세요!

AWS를 이용하는 방법

AWS를 이용하는 방법에는 크게 3가지 방법이 있습니다. 여기에서는 실제 웹에서 로그인하는 AWS console 방식을 제외하고 AWS CLI, AWS SDK를 이용하고 공부하는 방법에 대해서 알아보겠습니다. 또한 개발 환경에 맞게 세팅하는 방법에 대해서 알아보겠습니다.

임시 자격 증명(AssumeRole)

개발시 사용하는 AWS 자격증명은 크게 두 가지가 있습니다.

  • Access key
  • AssumeRole

Access key를 사용하는 경우는 유출시 치명적이므로, 반드시 AssumeRole을 이용해서 토큰을 발급받아 사용합시다. Assume의 대상인 역할(Role) 또한 필요한 최소 권한만 설정하는게 바람직합니다.

AWS CLI : AssumeRole

AWS CLI에서 아래의 명령을 통해 JSON 형태의 토큰을 발급 받을 수 있습니다. 하지만 토큰을 받아서 다시 그 토큰을 환경변수에 등록하기는 무척이나 번거롭습니다. 게다가 토큰의 최대 만료시간은 12시간이기 때문에 필요할때마다 매번 해당 작업을 반복해야 합니다.

$ aws sts assume-role --role-arn <ROLE_ARN> --role-session-name <session-name>
{
    "Credentials": {
        "AccessKeyId": "ASIA.......",
        "SecretAccessKey": "YwyGY8dF5.......",
        "SessionToken": "IQoJb3JpZ2.......",
        "Expiration": "2024-04-21T08:08:12Z"
    },
}

AssumeRole 스크립트 작성

AssumeRole에서 필요한 3가지 값은 다음과 같습니다. 이 값들을 자동으로 환경변수에 등록하는 스크립트를 작성해봅시다.

  • Credentials.AccessKeyId
  • Credentials.SecretAccessKey
  • Credentials.SessionToken

JSON 데이터를 처리하는 jq 패키지를 설치하고 스크립트를 작성합니다. $()는 쉘 스크립트에서 명령어 치환(Command Substitution)을 위해 사용되는 구문입니다. 이 구문은 괄호 안의 명령어를 실행하고, 그 결과를 출력합니다.

$ROLE_ARN 환경변수는 해당 스크립트가 실행 될때 원하는 역할(Role)을 입력 받을 수 있게 만들어둡니다.

jq -r 옵션은 출력을 raw 문자열로 반환하라는 의미입니다. 기본적으로 jq는 JSON 문자열 형태로 따옴표로 둘러싸여 있습니다. 하지만 -r 옵션을 사용하면, 따옴표 없이 raw 문자열을 출력합니다. 따옴표 없는 raw 형태의 토큰을 export를 수행해서 AWS CLI에서 사용하는 환경변수명으로 등록 합니다.

$ apt install jq
#!/bin/bash

output=$(aws sts assume-role --role-arn $ROLE_ARN --role-session-name cli-assume-session)

export AWS_ACCESS_KEY_ID=$(echo $output | jq -r '.Credentials.AccessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo $output | jq -r '.Credentials.SecretAccessKey')
export AWS_SESSION_TOKEN=$(echo $output | jq -r '.Credentials.SessionToken')

실행할때는 ROLE_ARN 환경변수에 원하는 역할 ARN 값을 입력합니다. source 명령으로 스크립트를 실행합니다. 현재 실행 중인 쉘에만 AssumeRole이 수행되고 환경변수값이 자동으로 세팅되는 것을 확인 할 수 있습니다. 쉘을 종료하거나 새로운 쉘에는 AssumeRole이 적용되지 않은 상태인 것을 기억하고 필요한 경우에는 해당 스크립트로 AssumeRole을 적용하면 됩니다.

$ export ROLE_ARN=arn:aws:iam::99842...:role/dev-assume-role-AmazonS3FullAccess

$ source ./scripts/set_assume_role.sh
$ echo AWS_SESSION_TOKEN

$ aws sts get-caller-identity

AWA CLI 디버깅

기본적으로 AWS CLI는 명령 출력의 명령 결과와 관련된 성공 또는 실패에 대한 정보를 제공합니다. --debug 옵션은 디버그 로깅을 활성화하는 옵션입니다. 아래의 명령을 통해 해당 로그를 파일로 저장할 수 있습니다.

  • stderr 진단 정보만 보내려면 2> 파일명
  • 출력과 stderr 진단 정보둘 다 보내려면 &> 파일명
aws s3 ls --debug 2> debug.txt

aws s3 ls --debug &> debug.txt

AWS SDK : AssumeRole

1. 패키지 설치

AWS SDK를 이용해서 AWS CLI와 동일하게 AssumeRole을 통해서 토큰을 발급받는 개발환경을 구축해보겠습니다. 여기서 사용되는 SDK는 python 패키지인 boto3입니다. 테스트에는 pytest와 python-dotenv를 사용하도록 하겠습니다. 필요한 패키지를 우선 설치합니다.

$ pip install boto3

$ pip install pytest python-dotenv

2. .env 파일 작성

.env 파일에 필요한 정보를 입력합니다. AssumeRole을 수행할 수 있는 Access key 정보를 입력하고 Role ARN 정보까지 입력합니다.

.env
AWS_ACCESS_KEY_ID=ASIA.......
AWS_SECRET_ACCESS_KEY=YwyGY8dF5.......

ROLE_ARN=arn:aws:iam::99842...:role/dev-assume-role-AmazonS3FullAccess

3. Access key 세션 생성

Access key를 사용하여 세션을 생성합니다. 이 세션을 fixture로 전달하여 다음 함수에서 AssumeRole을 수행합니다.

tests/conftest.py
import logging
import pytest

import os
from dotenv import load_dotenv

import boto3
from boto3 import Session

# .env 파일 로드
load_dotenv()
@pytest.fixture(scope="session", name="aws_user_session")
def setup_user_session() -> Session:
    aws_access_key_id = os.getenv("AWS_ACCESS_KEY_ID")
    aws_secret_access_key = os.getenv("AWS_SECRET_ACCESS_KEY")
    region_name = os.getenv("REGION_NAME")

    return boto3.Session(
        aws_access_key_id=aws_access_key_id,
        aws_secret_access_key=aws_secret_access_key,
        region_name=region_name,
    )

4. AssumeRole을 통한 토큰생성 및 세션 생성

세션을 통해 AssumeRole을 수행합니다. 그 결과 발급된 토큰 Credentials을 사용하여 다시 새로운 세션을 만듭니다. 이 세션값을 통해 테스트를 수행 할 수 있습니다.

tests/conftest.py
@pytest.fixture(scope="session", name="assume_role_session")
def setup_role_credentials(aws_user_session: Session):
    role_arn = os.getenv("ROLE_ARN")

    credentials = assume_role(aws_user_session, role_arn)

    session = boto3.Session(
        aws_access_key_id=credentials["AccessKeyId"],
        aws_secret_access_key=credentials["SecretAccessKey"],
        aws_session_token=credentials["SessionToken"],
        region_name=os.getenv("AWS_REGION"),
    )

    logging.info("Role credentials are generated successfully")

    sts = session.client("sts")
    logging.info(sts.get_caller_identity())

    return session
def assume_role(aws_user_session: Session, role_arn: str):
    sts_client = aws_user_session.client("sts")

    response = sts_client.assume_role(
        RoleArn=role_arn, RoleSessionName="boto3-assume-session"
    )

    return response["Credentials"]

5. AssumeRole 세션

이제 AssumeRole을 통해 전환된 세션에 할당된 권한으로 개발을 진행합니다. 아래의 코드는 SecureGroup을 가져와서 출력하는 기능을 테스트하는 코드입니다.

src/ec2.py
import logging
def hello_ec2(ec2_resource):
    logging.info("Hello, Amazon EC2! Let's list up to 10 of your security groups:")
    for sg in ec2_resource.security_groups.limit(10):
        logging.info(f"\t{sg.id}: {sg.group_name}")
tests/test_ec2.py
import pytest

from src.ec2 import hello_ec2
class TestEC2:
    @pytest.fixture(autouse=True)
    def setup(self, assume_role_session):
        self.session = assume_role_session
        self.ec2_resource = session.resource("ec2")

    def test_hello_ec2(self):
        hello_ec2(self.ec2_resource)

마무리

Access key를 그대로 개발환경에 사용하는 것은 보안상 위험할 수 있습니다. 따라서 AssumeRole을 통한 개발환경을 구축하는 것이 바람직합니다.

여기서는 AWS CLI와 AWS SDK에서 AssumeRole을 통해 발급받은 토큰을 활용하는 개발환경을 구축했습니다. 이제 구성된 환경을 바탕으로 아래의 URL 링크를 통해서 더 많은 AWS 서비스를 직접 사용하고 공부해 보시길 바랍니다! 😊

AWS CLI

AWS SDK

Want to know more about 'AssumeRole'? Check out "AWS Temporary Credentials (AssumeRole)"!

Ways to Use AWS

There are three main ways to use AWS. Leaving aside the AWS console, where you sign in on the web, this post looks at how to use and study AWS with the AWS CLI and the AWS SDK, and how to set them up for a development environment.

Temporary Credentials (AssumeRole)

There are two main kinds of AWS credentials used in development:

  • Access key
  • AssumeRole

An Access key is fatal if it leaks, so always use AssumeRole to get a token instead. The role you assume should also have only the minimum permissions it needs.

AWS CLI: AssumeRole

In the AWS CLI, the command below issues a token in JSON form. But taking that token and registering it in environment variables by hand is a real chore. On top of that, a token lasts 12 hours at most, so you’d have to repeat this every time you need it.

$ aws sts assume-role --role-arn <ROLE_ARN> --role-session-name <session-name>
{
    "Credentials": {
        "AccessKeyId": "ASIA.......",
        "SecretAccessKey": "YwyGY8dF5.......",
        "SessionToken": "IQoJb3JpZ2.......",
        "Expiration": "2024-04-21T08:08:12Z"
    },
}

Writing an AssumeRole Script

AssumeRole gives you these three values. Let’s write a script that registers them as environment variables automatically.

  • Credentials.AccessKeyId
  • Credentials.SecretAccessKey
  • Credentials.SessionToken

Install the jq package, which processes JSON data, and write the script. $() is shell syntax for command substitution: it runs the command inside the parentheses and outputs the result.

The $ROLE_ARN environment variable lets you pass in the role you want when the script runs.

The jq -r option means “return raw strings”. By default, jq prints JSON strings wrapped in quotes. With -r, it prints raw strings without the quotes. We then export the unquoted tokens under the environment variable names the AWS CLI uses.

$ apt install jq
#!/bin/bash

output=$(aws sts assume-role --role-arn $ROLE_ARN --role-session-name cli-assume-session)

export AWS_ACCESS_KEY_ID=$(echo $output | jq -r '.Credentials.AccessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo $output | jq -r '.Credentials.SecretAccessKey')
export AWS_SESSION_TOKEN=$(echo $output | jq -r '.Credentials.SessionToken')

To run it, put the ARN of the role you want in the ROLE_ARN environment variable and run the script with source. AssumeRole runs only in the current shell, and the environment variables are set automatically. Remember that when you exit the shell or open a new one, AssumeRole isn’t applied there; just run the script again whenever you need it.

$ export ROLE_ARN=arn:aws:iam::99842...:role/dev-assume-role-AmazonS3FullAccess

$ source ./scripts/set_assume_role.sh
$ echo AWS_SESSION_TOKEN

$ aws sts get-caller-identity

Debugging the AWS CLI

By default, the AWS CLI reports whether a command succeeded or failed in its output. The --debug option turns on debug logging. The commands below save that log to a file.

  • To send only the stderr diagnostics: 2> filename
  • To send both the output and the stderr diagnostics: &> filename
aws s3 ls --debug 2> debug.txt

aws s3 ls --debug &> debug.txt

AWS SDK: AssumeRole

1. Install packages

Let’s build a development environment where the AWS SDK gets a token through AssumeRole, just like the AWS CLI. The SDK here is the Python package boto3. For testing, we’ll use pytest and python-dotenv. Install the packages first.

$ pip install boto3

$ pip install pytest python-dotenv

2. Write the .env file

Put the information you need in the .env file: the access key that is allowed to run AssumeRole, and the role ARN.

.env
AWS_ACCESS_KEY_ID=ASIA.......
AWS_SECRET_ACCESS_KEY=YwyGY8dF5.......

ROLE_ARN=arn:aws:iam::99842...:role/dev-assume-role-AmazonS3FullAccess

3. Create a session with the access key

Create a session using the access key. We pass this session on as a fixture so the next function can run AssumeRole.

tests/conftest.py
import logging
import pytest

import os
from dotenv import load_dotenv

import boto3
from boto3 import Session

# Load the .env file
load_dotenv()
@pytest.fixture(scope="session", name="aws_user_session")
def setup_user_session() -> Session:
    aws_access_key_id = os.getenv("AWS_ACCESS_KEY_ID")
    aws_secret_access_key = os.getenv("AWS_SECRET_ACCESS_KEY")
    region_name = os.getenv("REGION_NAME")

    return boto3.Session(
        aws_access_key_id=aws_access_key_id,
        aws_secret_access_key=aws_secret_access_key,
        region_name=region_name,
    )

4. Get a token with AssumeRole and create a session

Run AssumeRole through the session. Then use the issued token, Credentials, to create a new session. You can run your tests with this session.

tests/conftest.py
@pytest.fixture(scope="session", name="assume_role_session")
def setup_role_credentials(aws_user_session: Session):
    role_arn = os.getenv("ROLE_ARN")

    credentials = assume_role(aws_user_session, role_arn)

    session = boto3.Session(
        aws_access_key_id=credentials["AccessKeyId"],
        aws_secret_access_key=credentials["SecretAccessKey"],
        aws_session_token=credentials["SessionToken"],
        region_name=os.getenv("AWS_REGION"),
    )

    logging.info("Role credentials are generated successfully")

    sts = session.client("sts")
    logging.info(sts.get_caller_identity())

    return session
def assume_role(aws_user_session: Session, role_arn: str):
    sts_client = aws_user_session.client("sts")

    response = sts_client.assume_role(
        RoleArn=role_arn, RoleSessionName="boto3-assume-session"
    )

    return response["Credentials"]

5. The AssumeRole session

Now you develop with the permissions assigned to the session you switched to through AssumeRole. The code below tests a function that fetches and prints security groups (SecureGroup).

src/ec2.py
import logging
def hello_ec2(ec2_resource):
    logging.info("Hello, Amazon EC2! Let's list up to 10 of your security groups:")
    for sg in ec2_resource.security_groups.limit(10):
        logging.info(f"\t{sg.id}: {sg.group_name}")
tests/test_ec2.py
import pytest

from src.ec2 import hello_ec2
class TestEC2:
    @pytest.fixture(autouse=True)
    def setup(self, assume_role_session):
        self.session = assume_role_session
        self.ec2_resource = session.resource("ec2")

    def test_hello_ec2(self):
        hello_ec2(self.ec2_resource)

Wrapping Up

Using an access key directly in your development environment can be a security risk. That’s why it’s better to build your development environment around AssumeRole.

Here we built a development environment where the AWS CLI and the AWS SDK use tokens issued through AssumeRole. With this setup in place, try out and study more AWS services yourself through the links below! 😊

AWS CLI

AWS SDK

AWS SDK

tiaz0128

Eat Sleep Coding.

Never Never GiveUp.

Security  |  BackEnd  |  Multi Cloud