CloudFormation 템플릿으로 SAML 페더레이션 역할 생성하기
CloudFormation 템플릿으로 SAML 페더레이션 역할 생성하기 (튜토리얼)
AWS 계정에 기존 SAML 자격 증명 공급자(IdP)가 구성되어 있다면 해당 IdP를 신뢰하는 페더레이션 IAM 역할을 만들 수 있어요. 이 튜토리얼은 CloudFormation 템플릿을 사용해 외부 IdP를 통해 인증된 사용자가 맡을 수 있는 SAML 페더레이션 IAM 역할을 만드는 방법을 보여줘요.
출처: 문서
본문
템플릿은 SAML IdP가 역할을 맡을 수 있게 허용하는 신뢰 정책이 있는 페더레이션 IAM 역할을 만들어요. 외부 IdP로 인증된 사용자는 역할의 권한에 따라 AWS 리소스에 접근하기 위해 이 역할을 맡을 수 있어요.
배포된 리소스는 다음으로 이루어져 있어요.
- 기존 SAML IdP를 신뢰하는 페더레이션 IAM 역할
- 역할에 연결해 특정 권한을 부여할 수 있는 구성 가능한 관리형 정책
- 선택적 권한 경계(permissions boundary)와 세션 기간 설정
사전 요구 사항 (Prerequisites)
이 튜토리얼은 다음이 이미 준비되어 있다고 가정해요.
- AWS 계정에 구성된 기존 SAML IdP. 없다면 IAM 튜토리얼 "CloudFormation 템플릿으로 SAML 자격 증명 공급자(IdP) 생성"을 사용해 만들 수 있어요.
- 스택을 만들 때 매개변수로 지정해야 하는 SAML IdP의 ARN
- 이 튜토리얼에서 IdP의 SAML 메타데이터 XML 파일을 포맷하는 데 사용하는 Python 명령을 실행할 로컬 머신에 설치된 Python 3.6 이상
CloudFormation으로 SAML 페더레이션 역할 생성 (Create a SAML federated role using CloudFormation)
SAML 페더레이션 역할을 만들려면 CloudFormation 템플릿을 만들고 이를 사용해 역할을 포함하는 스택을 만들어요.
템플릿 생성 (Create the template)
먼저 CloudFormation 템플릿을 만들어요.
- Template 섹션에서 JSON 또는 YAML 탭의 복사 아이콘을 클릭해 템플릿 내용을 복사해요.
- 템플릿 내용을 새 파일에 붙여넣어요.
- 파일을 로컬에 저장해요.
스택 생성 (Create the stack)
다음으로 저장한 템플릿을 사용해 CloudFormation 스택을 프로비저닝해요.
- https://console.aws.amazon.com/cloudformation 에서 CloudFormation 콘솔을 열어요.
- Stacks 페이지에서 Create stack 메뉴에서 **with new resources (standard)**를 선택해요.
- 템플릿을 지정해요:
- Prerequisite 아래에서 Choose an existing template을 선택해요.
- Specify template 아래에서 Upload a template file을 선택해요.
- Choose file을 선택하고 템플릿 파일로 이동한 뒤 선택해요.
- Next를 선택해요.
- 다음 스택 세부 정보를 지정해요:
- 스택 이름을 입력해요.
- SAMLProviderARN에 기존 SAML IdP의 ARN을 입력해요. 형식은
arn:aws:iam::123456789012:saml-provider/YourProviderName이어야 해요. 예:arn:aws:iam::123456789012:saml-provider/CompanyIdP참고 – IAM 튜토리얼 "CloudFormation 템플릿으로 SAML 자격 증명 공급자(IdP) 생성"으로 SAML IdP를 만들었다면 해당 CloudFormation 스택의 Outputs 탭에서 공급자 ARN을 찾을 수 있어요.
- RoleName은 비워 두면 스택 이름을 기반으로 이름이 자동 생성되거나, IAM 역할에 사용자 지정 이름을 입력할 수 있어요. 예:
SAML-Developer-Access또는SAML-ReadOnly-Role - 다른 매개변수는 요구 사항에 따라 기본값을 수락하거나 직접 입력해요:
- RoleSessionDuration – 최대 세션 기간(초) (3600-43200, 기본값 7200) 예:
14400(4시간) - RolePermissionsBoundary – 권한 경계 정책의 선택적 ARN 예:
arn:aws:iam::123456789012:policy/DeveloperBoundary - RolePath – IAM 역할의 경로 (기본값은 /) 예:
/saml-roles/ - ManagedPolicy1-5 – 연결할 최대 5개 관리형 정책의 선택적 ARN. ManagedPolicy1의 예:
arn:aws:iam::aws:policy/ReadOnlyAccess. ManagedPolicy2의 예:arn:aws:iam::123456789012:policy/CustomPolicy
- RoleSessionDuration – 최대 세션 기간(초) (3600-43200, 기본값 7200) 예:
- Next를 선택해요.
- 스택 옵션을 구성해요:
- Stack failure options 아래에서 Delete all newly created resources를 선택해요.
참고 – 이 옵션을 선택하면 스택 생성이 실패해도 삭제 정책이 리소스를 보관하도록 지정된 리소스에 대해 요금이 부과되는 것을 방지할 수 있어요.
- 다른 모든 기본값을 수락해요.
- Capabilities 아래에서 CloudFormation이 계정에 IAM 리소스를 만들 수 있음을 인정하는 확인란을 선택해요.
- Next를 선택해요.
- Stack failure options 아래에서 Delete all newly created resources를 선택해요.
- 스택 세부 정보를 검토하고 Submit을 선택해요.
- CloudFormation이 스택을 만들어요. 스택 생성이 완료되면 스택 리소스를 사용할 준비가 돼요. 스택 상세 페이지의 Resources 탭을 사용해 계정에 프로비저닝된 리소스를 볼 수 있어요.
스택은 다음 값을 출력하며 Outputs 탭에서 볼 수 있어요.
- RoleARN: 생성된 IAM 역할의 ARN(예:
arn:aws:iam::123456789012:role/SAML-Developer-Access, 자동 생성 이름을 사용하면arn:aws:iam::123456789012:role/stack-name-a1b2c3d4).
이 역할 ARN은 IdP가 역할 전환용 적절한 SAML 속성을 보내도록 구성할 때 필요해요.
SAML 페더레이션 역할 테스트 (Test the SAML federated role)
SAML 페더레이션 역할을 만든 후에는 구성을 확인하고 페더레이션 설정을 테스트할 수 있어요.
- https://console.aws.amazon.com/iam/ 에서 IAM 콘솔을 열어요.
- 탐색 창에서 Roles를 선택해요.
- 새로 만든 페더레이션 역할을 찾아 선택해요. 사용자 지정 역할 이름을 제공했다면 그 이름을 찾아요. RoleName 매개변수를 비워 두었다면 역할에는 스택 이름과 고유 식별자를 기반으로 한 자동 생성 이름이 있어요.
- Trust relationships 탭을 선택해 신뢰 정책을 검토해요.
- 신뢰 정책은 SAML IdP가 신뢰받아 이 역할을 맡을 수 있고, SAML 대상(
SAML:aud)이https://signin.aws.amazon.com/saml과 일치한다는 조건이 있는지 보여줘야 해요. - Permissions 탭을 선택해 연결된 정책을 검토해요. 생성 중 역할에 연결된 모든 관리형 정책을 볼 수 있어요.
- 역할 요약 페이지에 표시된 Role ARN을 기록해요. 외부 IdP가 사용자가 이 역할을 맡을 수 있게 구성하려면 이 ARN이 필요해요.
이제 SAML 페더레이션 역할을 사용할 준비가 됐어요. 외부 IdP가 SAML 어서션에 이 역할의 ARN을 포함하도록 구성하면 인증된 사용자가 이 역할을 맡아 AWS 리소스에 접근할 수 있게 돼요.
정리: 리소스 삭제 (Clean up: delete resources)
마지막 단계로 스택과 그 안에 포함된 리소스를 삭제해요.
- CloudFormation 콘솔을 열어요.
- Stacks 페이지에서 템플릿으로 만든 스택을 선택하고 Delete를 선택한 뒤 Delete를 확인해요.
- CloudFormation이 스택과 여기에 포함된 모든 리소스의 삭제를 시작해요.
CloudFormation 템플릿 세부 정보 (CloudFormation template details)
리소스 (Resources)
이 튜토리얼의 CloudFormation 템플릿은 계정에 다음 리소스를 만들어요.
AWS::IAM::Role: SAML IdP를 통해 인증된 사용자가 맡을 수 있는 페더레이션 IAM 역할
구성 (Configuration)
템플릿은 다음 구성 가능한 매개변수를 포함해요.
- RoleName – IAM 역할의 이름 (자동 생성 이름을 위해 비워 두기)
- SAMLProviderARN – SAML IdP의 ARN (필수)
- RoleSessionDuration – 최대 세션 기간(초) (3600-43200, 기본값 7200)
- RolePermissionsBoundary – 권한 경계 정책의 선택적 ARN
- RolePath – IAM 역할의 경로 (기본값 /)
- ManagedPolicy1-5 – 연결할 최대 5개 관리형 정책의 선택적 ARN
CloudFormation 템플릿 (CloudFormation template)
이 튜토리얼의 CloudFormation 템플릿으로 사용할 다음 JSON 또는 YAML 코드를 별도 파일로 저장해요.
JSON
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "[AWSDocs] IAM: tutorial_saml-federated-role",
"Parameters": {
"RoleName": {
"Type": "String",
"Description": "Name of the IAM Role (leave empty for auto-generated name like '{StackName}-{UniqueId}')",
"Default": "",
"AllowedPattern": "^$|^[\\w+=,.@-]{1,64}$",
"ConstraintDescription": "Must be empty or 1-64 characters and can contain alphanumeric characters and +=,.@-"
},
"SAMLProviderARN": {
"Type": "String",
"Description": "ARN of the SAML Identity Provider",
"AllowedPattern": "^arn:aws:iam::\\d{12}:saml-provider/[a-zA-Z0-9._-]+$",
"ConstraintDescription": "Must be a valid SAML provider ARN"
},
"RoleSessionDuration": {
"Type": "Number",
"Description": "The maximum session duration (in seconds) that you want to set for the specified role (3600-43200)",
"MinValue": 3600,
"MaxValue": 43200,
"Default": 7200
},
"RolePermissionsBoundary": {
"Type": "String",
"Description": "Optional ARN of the permissions boundary policy (leave empty for none)",
"Default": ""
},
"RolePath": {
"Type": "String",
"Description": "Path for the IAM role (must start and end with /)",
"Default": "/",
"AllowedPattern": "^\\/.*\\/$|^\\/$",
"ConstraintDescription": "Role path must start and end with forward slash (/)"
},
"RoleManagedPolicy1": {
"Type": "String",
"Description": "Optional managed policy ARN 1",
"Default": ""
},
"RoleManagedPolicy2": {
"Type": "String",
"Description": "Optional managed policy ARN 2",
"Default": ""
},
"RoleManagedPolicy3": {
"Type": "String",
"Description": "Optional managed policy ARN 3",
"Default": ""
},
"RoleManagedPolicy4": {
"Type": "String",
"Description": "Optional managed policy ARN 4",
"Default": ""
},
"RoleManagedPolicy5": {
"Type": "String",
"Description": "Optional managed policy ARN 5",
"Default": ""
}
},
"Conditions": {
"HasCustomRoleName": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleName"}, ""]}]},
"HasPermissionsBoundary": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RolePermissionsBoundary"}, ""]}]},
"HasPolicy1": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleManagedPolicy1"}, ""]}]},
"HasPolicy2": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleManagedPolicy2"}, ""]}]},
"HasPolicy3": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleManagedPolicy3"}, ""]}]},
"HasPolicy4": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleManagedPolicy4"}, ""]}]},
"HasPolicy5": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleManagedPolicy5"}, ""]}]}
},
"Resources": {
"SAMLFederatedRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"RoleName": {"Fn::If": ["HasCustomRoleName", {"Ref": "RoleName"}, {"Ref": "AWS::NoValue"}]},
"Description": "IAM role with SAML provider trust",
"MaxSessionDuration": {"Ref": "RoleSessionDuration"},
"PermissionsBoundary": {"Fn::If": ["HasPermissionsBoundary", {"Ref": "RolePermissionsBoundary"}, {"Ref": "AWS::NoValue"}]},
"Path": {"Ref": "RolePath"},
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": {"Ref": "SAMLProviderARN"}
},
"Action": "sts:AssumeRoleWithSAML",
"Condition": {
"StringEquals": {
"SAML:aud": "https://signin.aws.amazon.com/saml"
}
}
}
]
},
"ManagedPolicyArns": {
"Fn::Split": [
",",
{
"Fn::Join": [
",",
[
{"Fn::If": ["HasPolicy1", {"Ref": "RoleManagedPolicy1"}, {"Ref": "AWS::NoValue"}]},
{"Fn::If": ["HasPolicy2", {"Ref": "RoleManagedPolicy2"}, {"Ref": "AWS::NoValue"}]},
{"Fn::If": ["HasPolicy3", {"Ref": "RoleManagedPolicy3"}, {"Ref": "AWS::NoValue"}]},
{"Fn::If": ["HasPolicy4", {"Ref": "RoleManagedPolicy4"}, {"Ref": "AWS::NoValue"}]},
{"Fn::If": ["HasPolicy5", {"Ref": "RoleManagedPolicy5"}, {"Ref": "AWS::NoValue"}]}
]
]
}
]
}
}
}
},
"Outputs": {
"RoleARN": {
"Description": "ARN of the created IAM Role",
"Value": {"Fn::GetAtt": ["SAMLFederatedRole", "Arn"]},
"Export": {
"Name": {"Fn::Sub": "${AWS::StackName}-RoleARN"}
}
}
}
}
YAML
AWSTemplateFormatVersion: '2010-09-09'
Description: '[AWSDocs] IAM: tutorial_saml-federated-role'
Parameters:
RoleName:
Type: String
Description: 'Name of the IAM Role (leave empty for auto-generated name like ''{StackName}-{UniqueId}'')'
Default: ""
AllowedPattern: '^$|^[\w+=,.@-]{1,64}$'
ConstraintDescription: 'Must be empty or 1-64 characters and can contain alphanumeric characters and +=,.@-'
SAMLProviderARN:
Type: String
Description: 'ARN of the SAML Identity Provider'
AllowedPattern: '^arn:aws:iam::\d{12}:saml-provider/[a-zA-Z0-9._-]+$'
ConstraintDescription: 'Must be a valid SAML provider ARN'
RoleSessionDuration:
Type: Number
Description: 'The maximum session duration (in seconds) that you want to set for the specified role (3600-43200)'
MinValue: 3600
MaxValue: 43200
Default: 7200
RolePermissionsBoundary:
Type: String
Description: Optional ARN of the permissions boundary policy (leave empty for none)
Default: ""
RolePath:
Type: String
Description: 'Path for the IAM role (must start and end with /)'
Default: "/"
AllowedPattern: '^\/.*\/$|^\/$'
ConstraintDescription: 'Role path must start and end with forward slash (/)'
RoleManagedPolicy1:
Type: String
Description: Optional managed policy ARN 1
Default: ""
RoleManagedPolicy2:
Type: String
Description: Optional managed policy ARN 2
Default: ""
RoleManagedPolicy3:
Type: String
Description: Optional managed policy ARN 3
Default: ""
RoleManagedPolicy4:
Type: String
Description: Optional managed policy ARN 4
Default: ""
RoleManagedPolicy5:
Type: String
Description: Optional managed policy ARN 5
Default: ""
Conditions:
HasCustomRoleName: !Not [!Equals [!Ref RoleName, ""]]
HasPermissionsBoundary: !Not [!Equals [!Ref RolePermissionsBoundary, ""]]
HasPolicy1: !Not [!Equals [!Ref RoleManagedPolicy1, ""]]
HasPolicy2: !Not [!Equals [!Ref RoleManagedPolicy2, ""]]
HasPolicy3: !Not [!Equals [!Ref RoleManagedPolicy3, ""]]
HasPolicy4: !Not [!Equals [!Ref RoleManagedPolicy4, ""]]
HasPolicy5: !Not [!Equals [!Ref RoleManagedPolicy5, ""]]
Resources:
SAMLFederatedRole:
Type: 'AWS::IAM::Role'
Properties:
RoleName: !If
- HasCustomRoleName
- !Ref RoleName
- !Ref AWS::NoValue
Description: 'IAM role with SAML provider trust'
MaxSessionDuration: !Ref RoleSessionDuration
PermissionsBoundary: !If
- HasPermissionsBoundary
- !Ref RolePermissionsBoundary
- !Ref AWS::NoValue
Path: !Ref RolePath
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Federated: !Ref SAMLProviderARN
Action: 'sts:AssumeRoleWithSAML'
Condition:
StringEquals:
'SAML:aud': 'https://signin.aws.amazon.com/saml'
ManagedPolicyArns:
!Split
- ','
- !Join
- ','
- - !If [HasPolicy1, !Ref RoleManagedPolicy1, !Ref 'AWS::NoValue']
- !If [HasPolicy2, !Ref RoleManagedPolicy2, !Ref 'AWS::NoValue']
- !If [HasPolicy3, !Ref RoleManagedPolicy3, !Ref 'AWS::NoValue']
- !If [HasPolicy4, !Ref RoleManagedPolicy4, !Ref 'AWS::NoValue']
- !If [HasPolicy5, !Ref RoleManagedPolicy5, !Ref 'AWS::NoValue']
Outputs:
RoleARN:
Description: 'ARN of the created IAM Role'
Value: !GetAtt SAMLFederatedRole.Arn
Export:
Name: !Sub '${AWS::StackName}-RoleARN'