메뉴

문서정보

목차

IAM

이제 우리는 퍼블릭 클라우드 서비스를 이용해서 인터넷상에 가상의 IDC를 만들고 그 위에 서비스를 구축할 수 있게됐다. 클라우드 제공업체는 컴퓨팅 파워, 스토리지, 네트워크, 애플리케이션, 개발 환경의 풀을 가지고 있으며 유저가 요청하면 이 풀에서 적당량만을 떼서 제공한다.

AWS는 기존의 IDC가 그랬던 것처럼 컴퓨팅파워, 스토리지, 네트워크등에 대해서 인증,접근,권한에 대한 완전한 기능 세트를 제공해야 한다. AWS는 AWS IAM를 이용해서 자원에 대한 인증,접근,권한 서비스를 제공한다.

AWS IAM은 Identity and Access Management의 줄임말이다. AWS의 독자적인 서비스용어는 아니고 비지니스 프로세스와 정책 기술에 대한 접근관리를 위한 일반적인 기술이다. IAM은 아래의 기능을 가져야 한다. AWS IAM이 아닌 소프트웨어 공학 관점에서 IAM의 기능을 설명하고 있지만, AWS IAM이라고 해서 이 범위를 벗어나는 것은 아니기 때문에 AWS IAM 서비스를 이해하는데 도움이 될 것이다.

유저는 AWS IAM을 이용해서, 자신의 컴퓨팅자원과 서비스들에 대한 계정,권한,제한 등을 설정 할 수 있다. 일반적인 인터넷 서비스의 경우 접근 유저는 그 자체가 온전한 하나의 실체이지만, AWS는 "IDC + 완전한 인터넷 서비스"라는 특성상 권한에 따른 그룹을 관리 할 수 있어야 한다. 예를 들어 모든 권한을 행사 할 수 있는 루트사용자가 있으며, 조직별로 제한된 권한을 가지는 사용자를 만들 수 있다.

AWS 계정을 처음 만들면 (인터넷 서비스 처럼) 모든 권한을 가진 단일 유저, 즉 "루트 유저"가 만들어진다. 루트유저는 모든 것을 할 수 있는 막강한 권한을 가진 만큼, 위험하기 때문에 일상적인 작업에서는 "그 작업에 필요한 자격증명서"를 따로 발급해서 업무를 수행한다. 리눅스 시스템에서 루트(root) 유저와 일반유저를 분리하는 것과 비슷 하다고 보면 되겠다.

이렇게 제한된 자격증명을 가지는 가상의 유저를 IAM 사용자(User)라고 한다. 루트 유저는 AWS 웹 콘솔 혹은 API를 이용해서 IAM 사용자를 만들 수 있다. IAM 사용자는 두 가지 타입이 있다.
  1. AWS Management 콘솔 접근 권한을 가지는 IAM 사용자 : 콘솔에 직접 들어가서 작업을 하는 "일반적인 사람"이다. 관리자나 개발자에게 부여하는 경우가 많다. 이들은 아이디와 패스워드로 웹 브라우저를 통해서 AWS 관리 콘솔에 접근, 콘솔이 제공하는 기능을 이용해서 자원을 관리한다.
  2. 프로그래밍 방식 접근을 위한 IAM 사용자 : 관리 콘솔로는 접근 할 수가 없다. AWS API나 CLI등 프로그래밍 방식을 이용해서 접근 할 수 있다. 일반적으로 사람이 아닌 자동화 프로그램, AWS 내부에서 작동하는 애플리케이션의 개발을 위해서 사용한다.
리눅스 계정 시스템과 비교하자면, 1번 타입의 유저는 ssh로 직접 접근 할 수 있는 계정이고 2번 타입의 유저는 nginx, mail, syslog 등 애플리케이션을 가동하기 위한 유저와 비슷하다. nginx, mail, syslog 등의 리눅스 계정은 shell이 없기 때문에 로그인 자체를 할 수 없다. 리눅스 계정과 마찬가지로 그룹을 만들어서 권한을 관리 할 수도 있다. 전반적으로 리눅스 계정 시스템과 매우 유사하다.

IAM 유저 생성

루트 유저는 IAM 유저를 만들 수 있다. IAM > Users 에서 IAM 유저를 확인 할 수 있다.

 Create User

 Create User

 Add user

 Add user

 Set permissions

 Set permissions

앞서 만든 유저 testuser에 대한 퍼미션(permission - 어떤 일을 할 수 있고, 어떤 일을 할 수 없는지)을 설정한다. 퍼미션에 대한 원칙은 "최소한의 권한만 할당하라"는 것이다. 예를 들어 S3 버킷에 저장된 파일을 다운로드 하는 애플리케이션을 위한 IAM은 "S3 버킷에 대한 읽기(readonly)권한"만 허가해야 한다. S3 버킷에 파일을 올려야 하는 관리자에게는 "S3 버킷에 대한 읽기/쓰기(read/write)"권한만 허가해야 한다. 버킷의 삭제, EC2에 대한 실행과 종료 등에 대한 권한을 주면 안된다.(귀찮아서 모든 것을 할 수 있는 Admin 권한을 주는 경우가 많다.)

Add Group: 좋은 방법은 그룹(group)을 만드는 거다. S3 작업을 위한 그룹, Route 53 설정을 위한 그룹, 빈스토크를 실행 할 수 있는 그룹등을 만들어서, 유저를 여기에 추가하면 일관성있는 권한 관리를 할 수 있다.

Copy permissions from existing user: 다른 유저의 권한을 복사해서 사용 할 수 있다.

Attach existing polices directly: 유저를 위한 권한을 직접 편집한다.

Attach existing plices directly를 선택해서 권한을 만들어 보자(Add group도 같은 방식으로 권한 정책을 만들면 된다). 클릭하면 AWS에서 제공하는 모든 정책들이 나열 된다. (2018년 5월)현재 무려 333개나 된다. "Search"를 이용해서 정책을 빠르게 찾을 수 있다.

 Attach existing policies

 Attach existing policies

S3에 접근하기 위한 IAM을 만들어보자. Attach existing policies directly로 이 유저에 직접 정책을 attach 하기로 했다. 정책 검색기능을 이용해서 S3 관련된 정책들을 찾았다. 읽기 전용이라면 "AmazonS3ReadOnlyAccess", 읽기/쓰기를 모두하고 싶다면 "AmazonS3FullAccess" 선택하면 된다. 이제 Reviews 단계에서 설정을 확인하고 "Create user"를 클릭하면 유저가 만들어진다.

 유저 정보

 유저 정보

Access Key ID와 Secret access key를 복사해서 (리눅스의 경우) $HOME/.aws/creddentials에 저장하면 된다.

IAM Key의 보관과 사용

여기에 있는 내용을 테스트하려면 AWS CLI 환경을 만들어야 한다. 링크를 참고해서 만들자.

IAM Key는 $HOME/.aws 디렉토리 밑에 저장한다. 여기에는 config 파일과 credentials 파일있다. config 파일은 리전이름과 출력형식을 저장하고 credentials 파일은 IAM Access key와 Secret access key를 저장하고 있다. AWS CLI 툴 과 AWS SDK 는 여기에 있는 값을 읽어서 AWS에 접근한다.
# cat config
[default]
region=ap-northeast-2
output=json

[profile joinc]
region=ap-northeast-2
output=json

# cat credentials
[default]
aws_access_key_id=AKxxxxxxxxxxxxxxxxxxxx
aws_secret_access_key=7Jsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

[joinc]
aws_access_key_id=AJxxxxxxxxxxxxxxxxxxxx
aws_secret_access_key=8kSxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
하나 이상의 IAM을 가질 수 있는데, profile로 사용할 IAM을 특정 할 수 있다. 위 예제는 default 와 joinc 두 개의 IAM을 설정했다. AWS CLI의 경우 profile을 설정 할 수 있으며, profile을 설정하지 않을 경우 default 값을 사용한다.
# aws --profile joinc s3 ls

S3를 기반으로 하는 파일 다운로드 서비스를 만들어야 한다고 가정해보자. 파일 업로드는 관리자만 할 수 있고, 일반 유저는 다운로드만 할 수 있다. 이 경우 애플리케이션 구성은 아래와 같을 거다.

 S3 IAM 구성

download server에는 ReaOnly 권한을 가지는 IAM의 Access key와 Secret access key를 $HOME/.aws 디렉토리 밑에 설정하면 된다.

계정(Account), 유저와 그룹

 계정, 유저와 그룹

계정, 유저, 그룹의 관계를 정리하고 넘어가자.

정책과 권한

앞서 S3에 대한 읽기전용 권한을 가지는 유저를 만들었다. 여기에서 우리는 IAM 유저가 작동하기 위해서 필요한 2가지 정보를 얻을 수 있다.
  1. 유저 : User name
  2. 정책 : AWS S3 자원에 읽기전용(ReadOnly)으로 접근 할 수 있는 정책
AWS IAM은 유저와 정책이 분리된다. 정책에는 특정 유저에 어떤 자원에, 어떤 권한을 허용할지에 대한 정보가 담겨있다. 정책은 JSON 형태로 저장된다. 정책은 다시 자격증명 기반 정책, 리소스 기반 정책, 권한 경계, 조직 SCP, 액세스 제어 목록(ACL), 세션 정책등으로 나뉜다. 예를 들어 S3나 CloudWatch의 사용에 대한 정책은 리소스 기반 정책으로 제어한다.

정책은 AWS에서 관리하는 AWS 관리형 정책과 유저가 필요에 따라 만드는 고객 관리형 정책이 있다. AWS에서 기본 제공하는 걸 사용하는지, 직접 만들어서 사용하는지에 대한 차이가 있을 뿐 다른 기술적인 차이는 없다. 아래는 정책관리에 대한 다이어그램이다.

 IAM 관리 다이어그램

Role의 사용은 밑에 장에서 자세히 다룬다.

S3 ReadOnly Policy의 내용을 살펴보자. 먼저 policy의 대략 정보를 확인한다.
> aws iam get-policy --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
{
    "Policy": {
        "PolicyName": "AmazonS3ReadOnlyAccess",
        "PolicyId": "ANPAIZTxxxxxxxxxxx",
        "Arn": "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess",
        "Path": "/",
        "DefaultVersionId": "v1",
        "AttachmentCount": 1,
        "PermissionsBoundaryUsageCount": 0,
        "IsAttachable": true,
        "Description": "Provides read only access to all buckets via the AWS Management Console.",
        "CreateDate": "2015-02-06T18:40:59Z",
        "UpdateDate": "2015-02-06T18:40:59Z"
    }
}
이제 AmazonS3ReadOnlyAccess policy의 세부 내용을 확인해 보자.
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:Get*",
                "s3:List*"
            ],
            "Resource": "*"
        }
    ]
}
s3:Gets3:List에 대한 액션을 모든(*) 리소스(AWS Resource)에 대해서 허용하고 있다. 모든 AWS 버킷에 대한 읽기 권한을 허용하겠다는 의미다. S3 버킷을 제한하고 싶다면, Resource에 S3 버킷의 ARN을 설정하면 된다. s3의 경우

Role을 이용한 안잔한 자원 접근

AWS API는 인터넷을 통한 접근을 허용한다. Key가 누출된다면, Key가 가진 권한도 탈취된다는 보안 취약점을 가지고 있다. 보안 취약점이 될 수 있기 때문에 두달 이상 계속 사용한 IAM에 대해서는 Key 변경 경고 메시지를 출력해서, Key를 변경하도록 경고메시지를 출력한다(리눅스 계정 Password에 만료기간을 두는 이유를 생각해 보자.)

하지만 Key를 주기적으로 변경은 쉽지 않다. 주의 깊게 Key를 관리하지 않는 한, 어떤 애플리케이션이 key를 사용하고 있는지 추적하기가 쉽지 않고, 추적한다고 하더라도 key를 변경한다는게 쉽지 않다.

이럴 때는 IAM Role을 사용하자. AWS에서 제공하는 EC2, RDS, DynamoDB와 같은 자원들은 메타데이터 항목을 가지고 있다. 이 메타데이터 항목에는 자원 식별자, MAC 주소, 네트워크 설정, Public/Private IP, Security group, 등등등 의 데이터를 가지고 있다. 또한 IAM:Role도 가지고 있는데. Role은 이 EC2는 "어떤 자원에 대해서 어떤 권한을 가지고 접근 할 수 있다"는 정보를 가지고 있다. 아래 그림을 보자.

 Role을 이용한 자원 접근

개발자는 S3 버킷에대한 ReadOnly 권한을 가진 Get-File롤을 만들었다. 이 롤은 EC2인스턴스의 메타 데이터로 저장된다. 애플리케이션이 실행되면, 메타데이터로 부터 Get-File롤에 대한 Credential을 가져올 수 있다. 이 Crendital을 이용해서 S3 버킷에 접근 한다. 이 방식의 장점은 아래와 같다.
  1. 설정파일 혹은 하드코딩의 형태로 IAM Key를 저장할 필요가 없다. 누출할 Key가 없어진다.
  2. 주기적인 Key 교체등의 관리작업이 필요없다.
  3. 새로 시작하는 인스턴스에 Key를 넣는 등의 작업이 필요없다.
이렇게 인스턴스에서 제공하는 자격증명은 임시자격 증명으로 만료시간을 가진다. AWS SDK를 이용 할 경우, 새 자격증명을 스스로 관리하기 때문에 애플리케이션에서 자격 증명 갱신을 위한 로직을 추가할 필요가 없다. 개발자는 애플리케이션에서 직접 임시 보안 자격 증명을 가져와서 사용 할 수도 있다. 만약 자격 증명을 캐시해서 사용하고 있다면, 현재의 자격증명이 만료되기 전에 갱신된 자격 증명을 가져와야 한다. 굳이 이렇게 할 필요가 있을지는 모르겠다. 그냥 SDK에 맡기자

 Role 만들기

 Role 만들기

Role 설정 페이지로 가보자. 이미 만들어진 몇 개 Role 들이 보인다. "Create role"을 클릭해서 Role을 만들 수 있다.

 Create role

 Create role

EC2, Lambda, API Gateway 같은 AWS 자원뿐만 아니라 Congnito, OpenID, SAML과 같은 인증/권한 서비스를 위한 role을 만들 수도 있다. Role을 적용하기 위한 자원의 타입을 선택하면 권한(Permissions)를 설정하는 화면이 나온다. 이 후 부터는 다른 IAM과 동일한 방식으로 설정을 진행하면 된다.

IAM 모범 사례

IAM 적용 모범 사례다.

 IAM Role 모범 사례

S3 접근 예제

S3 버킷에서 파일 목록을 읽어와서 작업을 하는 Go 애플리케이션을 만들기로 했다. 이 애플리케이션을 위해서 S3 Readonly Role을 만들어서 인스턴스에 설정한다.

아래와 같이 모든 S3 버켓에 대해서 ReadOnly(Get, List)할 수 있는 롤을 만들었다. 롤의 이름은 ec2_s3_readonly로 했다.
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:Get*",
                "s3:List*"
            ],
            "Resource": "*"
        }
    ]
}
인스턴스를 만들 때, ec2_s3_readonly Role을 설정한다.

 EC2 IAM

 EC2 IAM

IAM role이 ec2_s3_readonly 임을 확인 할 수 있다. EC2 인스턴스에 접근해서 Role 정보를 확인해 보자.

실행 중인 인스턴스에서는 아래 URI에서 메타 정보를 가져올 수 있다.
http://169.254.169.254/latest/meta-data/
curl 로 iam 정보를 읽었다.
$ curl http://169.254.169.254/latest/meta-data/iam/info
{
  "Code" : "Success",
  "LastUpdated" : "2019-03-06T14:12:50Z",
  "InstanceProfileArn" : "arn:aws:iam::522373083963:instance-profile/ec2_s3_readonly",
  "InstanceProfileId" : "AIPAJW55WPXT3IYBGJ46W"
}
해당 인스턴스에 ec2_s3_readonly Role이 할당됐음을 알 수 있다. aws cli 툴로 s3 정보를 읽어보자.
$ aws s3 ls
2019-02-01 14:22:02 codepipeline-ap-northeast-2-69042581008
2018-12-03 13:34:14 storage.joinc.s3
Credential 설정을 하지 않았는데도 s3 파일을 읽을 수 있다.

애플리케이션 테스트를 위해서 간단한 다운로드 프로그램을 만들었다.
package main

import (
	"fmt"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/endpoints"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
	"os"
)

func main() {
	if len(os.Args) != 2 {
		fmt.Println("Usage : ", os.Args[0], "filename")
		os.Exit(1)
	}
	filename := os.Args[1]
	file, err := os.Create(filename)
	if err != nil {
		fmt.Println("file open error", err)
		os.Exit(0)
	}
	defer file.Close()

	s := session.New(&aws.Config{Region: aws.String(endpoints.ApNortheast2RegionID)})
	downloader := s3manager.NewDownloader(s)
	numBytes, err := downloader.Download(file,
		&s3.GetObjectInput{
			Bucket: aws.String("storage.joinc.s3"),
			Key:    aws.String(filename),
		},
	)
	if err != nil {
		fmt.Println("Download Error", err)
	} else {
		fmt.Println("Read Byte", numBytes)
	}
}
이 코드는 storage.joinc.s3 버켓에 있는 파일을 다운로드한다. 먼저 로컬PC 에서 실행을 했다. 현재 로컬 PC에는 AWS Credential 설정이 없다.
# ./downloader file.go
Download Error NoCredentialProviders: no valid providers in chain. Deprecated.
	For verbose messaging see aws.Config.CredentialsChainVerboseErrors

Credentail이 없어서 버킷에 접근 할 수 없다는 에러가 출력된다. 이 프로그램을 위에서 만든 EC2에 복사해서 실행했다.
[ec2-user@ip-10-10-0-9 ~]$ ./downloader file.go
Read Byte 770
접근 성공!!

문서 내용 정리

AWS IAM FAQ 정리

IAM FAQ에서 중요 하다 싶은 것들만 정리 했다.

참고