시스템 관리 설정하기

시스템 관리 설정하기

이 코드 예제에서는 AWS CLI로 AWS Systems Manager를 설정하는 방법을 보여드려요.

출처: 문서

본문

다음 작업을 다루어요.

  • Systems Manager용 IAM 권한 생성
  • Systems Manager용 IAM 역할 생성
  • Systems Manager 구성
  • 설정 검증
  • 리소스 정리

Bash (AWS CLI with Bash script)

Note GitHub에 더 많은 내용이 있어요. 전체 예제와 설정·실행 방법은 Sample developer tutorials 저장소에서 확인할 수 있어요.

이 스크립트는 Systems Manager 온보딩에 필요한 IAM 정책·역할을 만들고, Host Management 구성을 사용해 Systems Manager Quick Setup 구성 관리자를 생성해요. ({), 롤(역할)이 CloudFormation을 신뢰하도록 trust policy에 cloudformation.amazonaws.com 서비스가 포함돼 있어요.

#!/bin/bash

# AWS Systems Manager Setup Script
# This script sets up AWS Systems Manager for a single account and region
#
# Version 17 fixes:
# 1. Added cloudformation.amazonaws.com to the IAM role trust policy
# 2. Systems Manager Quick Setup uses CloudFormation for deployments, so the role must trust CloudFormation service

# Initialize log file
LOG_FILE="ssm_setup_$(date +%Y%m%d_%H%M%S).log"
UNIQUE_ID=$(openssl rand -hex 4)
echo "Starting AWS Systems Manager setup at $(date)" > "$LOG_FILE"

# Function to log commands and their outputs with immediate terminal display
log_cmd() {
	echo "$(date): Running command: $1" | tee -a "$LOG_FILE"
	local output
	output=$(eval "$1" 2>&1)
	local status=$?
	echo "$output" | tee -a "$LOG_FILE"
	return $status
}

# Function to check for errors in command output
check_error() {
	local cmd_output="$1"
	local cmd_status="$2"
	local error_msg="$3"

	if [[ $cmd_status -ne 0 || "$cmd_output" =~ [Ee][Rr][Rr][Oo][Rr] ]]; then
		echo "ERROR: $error_msg" | tee -a "$LOG_FILE"
		echo "Command output: $cmd_output" | tee -a "$LOG_FILE"
		cleanup_on_error
		exit 1
	fi
}

# Array to track created resources for cleanup
declare -a CREATED_RESOURCES

# Function to add a resource to the tracking array
track_resource() {
	local resource_type="$1"
	local resource_id="$2"
	CREATED_RESOURCES+=("$resource_type:$resource_id")
	echo "Tracked resource: $resource_type:$resource_id" | tee -a "$LOG_FILE"
}

# Function to clean up resources on error
cleanup_on_error() {
	echo "" | tee -a "$LOG_FILE"
	echo "==========================================" | tee -a "$LOG_FILE"
	echo "ERROR OCCURRED - CLEANING UP RESOURCES" | tee -a "$LOG_FILE"
	echo "==========================================" | tee -a "$LOG_FILE"
	echo "The following resources were created:" | tee -a "$LOG_FILE"

	# Display resources in reverse order
	for ((i=${#CREATED_RESOURCES[@]}-1; i>=0; i--)); do
		echo "${CREATED_RESOURCES[$i]}" | tee -a "$LOG_FILE"
	done

	echo "" | tee -a "$LOG_FILE"
	echo "Attempting to clean up resources..." | tee -a "$LOG_FILE"

	# Clean up resources in reverse order
	cleanup_resources
}

# Function to clean up all created resources
cleanup_resources() {
	# Process resources in reverse order (last created, first deleted)
	for ((i=${#CREATED_RESOURCES[@]}-1; i>=0; i--)); do
		IFS=':' read -r resource_type resource_id <<< "${CREATED_RESOURCES[$i]}"

		echo "Deleting $resource_type: $resource_id" | tee -a "$LOG_FILE"

		case "$resource_type" in
		"IAM_POLICY")
			# Delete the policy (detachment should have been handled when the role was deleted)
			log_cmd "aws iam delete-policy --policy-arn $resource_id" || true
			;;
		"IAM_ROLE")
			# Detach all policies from the role first
			if [[ -n "$POLICY_ARN" ]]; then
				log_cmd "aws iam detach-role-policy --role-name $resource_id --policy-arn $POLICY_ARN" || true
			fi

			# Delete the role
			log_cmd "aws iam delete-role --role-name $resource_id" || true
			;;
		"SSM_CONFIG_MANAGER")
			log_cmd "aws ssm-quicksetup delete-configuration-manager --manager-arn $resource_id" || true
			;;
		*)
			echo "Unknown resource type: $resource_type, cannot delete automatically" | tee -a "$LOG_FILE"
			;;
		esac
	done

	echo "Cleanup completed" | tee -a "$LOG_FILE"

	# Clean up temporary files
	rm -f ssm-onboarding-policy.json trust-policy.json ssm-config.json 2>/dev/null || true
}

# Main script execution
echo "AWS Systems Manager Setup Script"
echo "================================"
echo "This script will set up AWS Systems Manager for a single account and region."
echo "It will create IAM policies and roles, then enable Systems Manager features."
echo ""

# Get the current AWS region
CURRENT_REGION=$(aws configure get region)
if [[ -z "$CURRENT_REGION" ]]; then
	echo "No AWS region configured. Please specify a region:"
	CURRENT_REGION="${AWS_DEFAULT_REGION:-us-west-2}"
	if [[ -z "$CURRENT_REGION" ]]; then
		echo "ERROR: A region must be specified" | tee -a "$LOG_FILE"
		exit 1
	fi
fi

echo "Using AWS region: $CURRENT_REGION" | tee -a "$LOG_FILE"

# Step 1: Create IAM policy for Systems Manager onboarding
echo "Step 1: Creating IAM policy for Systems Manager onboarding..."

# Create policy document
cat > ssm-onboarding-policy.json << 'EOF'
{
	"Version":"2012-10-17",
	"Statement": [
		{
			"Sid": "QuickSetupActions",
			"Effect": "Allow",
			"Action": [
				"ssm-quicksetup:*"
			],
			"Resource": "*"
		},
		{
			"Sid": "SsmReadOnly",
			"Effect": "Allow",
			"Action": [
				"ssm:DescribeAutomationExecutions",
				"ssm:GetAutomationExecution",
				"ssm:ListAssociations",
				"ssm:DescribeAssociation",
				"ssm:ListDocuments",
				"ssm:ListResourceDataSync",
				"ssm:DescribePatchBaselines",
				"ssm:GetPatchBaseline",
				"ssm:DescribeMaintenanceWindows",
				"ssm:DescribeMaintenanceWindowTasks"
			],
			"Resource": "*"
		},
		{
			"Sid": "SsmDocument",
			"Effect": "Allow",
			"Action": [
				"ssm:GetDocument",
				"ssm:DescribeDocument"
			],
			"Resource": [
				"arn:aws:ssm:*:*:document/AWSQuickSetupType-*",
				"arn:aws:ssm:*:*:document/AWS-EnableExplorer"
			]
		},
		{
			"Sid": "SsmEnableExplorer",
			"Effect": "Allow",
			"Action": "ssm:StartAutomationExecution",
			"Resource": "arn:aws:ssm:*:*:automation-definition/AWS-EnableExplorer:*"
		},
		{
			"Sid": "SsmExplorerRds",
			"Effect": "Allow",
			"Action": [
				"ssm:GetOpsSummary",
				"ssm:CreateResourceDataSync",
				"ssm:UpdateResourceDataSync"
			],
			"Resource": "arn:aws:ssm:*:*:resource-data-sync/AWS-QuickSetup-*"
		},
		{
			"Sid": "OrgsReadOnly",
			"Effect": "Allow",
			"Action": [
				"organizations:DescribeAccount",
				"organizations:DescribeOrganization",
				"organizations:ListDelegatedAdministrators",
				"organizations:ListRoots",
				"organizations:ListParents",
				"organizations:ListOrganizationalUnitsForParent",
				"organizations:DescribeOrganizationalUnit",
				"organizations:ListAWSServiceAccessForOrganization"
			],
			"Resource": "*"
		},
		{
			"Sid": "OrgsAdministration",
			"Effect": "Allow",
			"Action": [
				"organizations:EnableAWSServiceAccess",
				"organizations:RegisterDelegatedAdministrator",
				"organizations:DeregisterDelegatedAdministrator"
			],
			"Resource": "*",
			"Condition": {
				"StringEquals": {
					"organizations:ServicePrincipal": [
						"ssm.amazonaws.com",
						"ssm-quicksetup.amazonaws.com",
						"member.org.stacksets.cloudformation.amazonaws.com",
						"resource-explorer-2.amazonaws.com"
					]
				}
			}
		},
		{
			"Sid": "CfnReadOnly",
			"Effect": "Allow",
			"Action": [
				"cloudformation:ListStacks",
				"cloudformation:DescribeStacks",
				"cloudformation:ListStackSets",
				"cloudformation:DescribeOrganizationsAccess"
			],
			"Resource": "*"
		},
		{
			"Sid": "OrgCfnAccess",
			"Effect": "Allow",
			"Action": [
				"cloudformation:ActivateOrganizationsAccess"
			],
			"Resource": "*"
		},
		{
			"Sid": "CfnStackActions",
			"Effect": "Allow",
			"Action": [
				"cloudformation:CreateStack",
				"cloudformation:DeleteStack",
				"cloudformation:DescribeStackResources",
				"cloudformation:DescribeStackEvents",
				"cloudformation:GetTemplate",
				"cloudformation:RollbackStack",
				"cloudformation:TagResource",
				"cloudformation:UntagResource",
				"cloudformation:UpdateStack"
			],
			"Resource": [
				"arn:aws:cloudformation:*:*:stack/StackSet-AWS-QuickSetup-*",
				"arn:aws:cloudformation:*:*:stack/AWS-QuickSetup-*",
				"arn:aws:cloudformation:*:*:type/resource/*"
			]
		},
		{
			"Sid": "CfnStackSetActions",
			"Effect": "Allow",
			"Action": [
				"cloudformation:CreateStackInstances",
				"cloudformation:CreateStackSet",
				"cloudformation:DeleteStackInstances",
				"cloudformation:DeleteStackSet",
				"cloudformation:DescribeStackInstance",
				"cloudformation:DetectStackSetDrift",
				"cloudformation:ListStackInstanceResourceDrifts",
				"cloudformation:DescribeStackSet",
				"cloudformation:DescribeStackSetOperation",
				"cloudformation:ListStackInstances",
				"cloudformation:ListStackSetOperations",
				"cloudformation:ListStackSetOperationResults",
				"cloudformation:TagResource",
				"cloudformation:UntagResource",
				"cloudformation:UpdateStackSet"
			],
			"Resource": [
				"arn:aws:cloudformation:*:*:stackset/AWS-QuickSetup-*",
				"arn:aws:cloudformation:*:*:type/resource/*",
				"arn:aws:cloudformation:*:*:stackset-target/AWS-QuickSetup-*:*"
			]
		},
		{
			"Sid": "ValidationReadonlyActions",
			"Effect": "Allow",
			"Action": [
				"iam:ListRoles",
				"iam:GetRole"
			],
			"Resource": "*"
		},
		{
			"Sid": "IamRolesMgmt",
			"Effect": "Allow",
			"Action": [
				"iam:CreateRole",
				"iam:DeleteRole",
				"iam:GetRole",
				"iam:AttachRolePolicy",
				"iam:DetachRolePolicy",
				"iam:GetRolePolicy",
				"iam:ListRolePolicies"
			],
			"Resource": [
				"arn:aws:iam::*:role/AWS-QuickSetup-*",
				"arn:aws:iam::*:role/service-role/AWS-QuickSetup-*"
			]
		},
		{
			"Sid": "IamPassRole",
			"Effect": "Allow",
			"Action": [
				"iam:PassRole"
			],
			"Resource": [
				"arn:aws:iam::*:role/AWS-QuickSetup-*",
				"arn:aws:iam::*:role/service-role/AWS-QuickSetup-*"
			],
			"Condition": {
				"StringEquals": {
					"iam:PassedToService": [
						"ssm.amazonaws.com",
						"ssm-quicksetup.amazonaws.com",
						"cloudformation.amazonaws.com"
					]
				}
			}
		},
		{
			"Sid": "IamRolesPoliciesMgmt",
			"Effect": "Allow",
			"Action": [
				"iam:AttachRolePolicy",
				"iam:DetachRolePolicy"
			],
			"Resource": [
				"arn:aws:iam::*:role/AWS-QuickSetup-*",
				"arn:aws:iam::*:role/service-role/AWS-QuickSetup-*"
			],
			"Condition": {
				"ArnEquals": {
					"iam:PolicyARN": [
						"arn:aws:iam::aws:policy/AWSSystemsManagerEnableExplorerExecutionPolicy",
						"arn:aws:iam::aws:policy/AWSQuickSetupSSMDeploymentRolePolicy"
					]
				}
			}
		},
		{
			"Sid": "CfnStackSetsSLR",
			"Effect": "Allow",
			"Action": [
				"iam:CreateServiceLinkedRole"
			],
			"Resource": [
				"arn:aws:iam::*:role/aws-service-role/stacksets.cloudformation.amazonaws.com/AWSServiceRoleForCloudFormationStackSetsOrgAdmin",
				"arn:aws:iam::*:role/aws-service-role/ssm.amazonaws.com/AWSServiceRoleForAmazonSSM",
				"arn:aws:iam::*:role/aws-service-role/accountdiscovery.ssm.amazonaws.com/AWSServiceRoleForAmazonSSM_AccountDiscovery",
				"arn:aws:iam::*:role/aws-service-role/ssm-quicksetup.amazonaws.com/AWSServiceRoleForSSMQuickSetup",
				"arn:aws:iam::*:role/aws-service-role/resource-explorer-2.amazonaws.com/AWSServiceRoleForResourceExplorer"
			]
		}
	]
}
EOF

# Create the IAM policy
POLICY_OUTPUT=$(log_cmd "aws iam create-policy --policy-name SSMOnboardingPolicy-$UNIQUE_ID --policy-document file://ssm-onboarding-policy.json --output json")
POLICY_STATUS=$?
check_error "$POLICY_OUTPUT" $POLICY_STATUS "Failed to create IAM policy"

# Extract the policy ARN
POLICY_ARN=$(echo "$POLICY_OUTPUT" | grep -o 'arn:aws:iam::[0-9]*:policy/SSMOnboardingPolicy-[a-f0-9]*')
if [[ -z "$POLICY_ARN" ]]; then
	echo "ERROR: Failed to extract policy ARN" | tee -a "$LOG_FILE"
	exit 1
fi

# Track the created policy
track_resource "IAM_POLICY" "$POLICY_ARN"
aws iam tag-policy --policy-arn "$POLICY_ARN" \
	--tags Key=project,Value=doc-smith Key=tutorial,Value=aws-systems-manager-gs

echo "Created policy: $POLICY_ARN" | tee -a "$LOG_FILE"

# Step 2: Create and configure IAM role for Systems Manager
echo ""
echo "Step 2: Creating IAM role for Systems Manager..."

# Get current user name
USER_OUTPUT=$(log_cmd "aws sts get-caller-identity --output json")
USER_STATUS=$?
check_error "$USER_OUTPUT" $USER_STATUS "Failed to get caller identity"

# Extract account ID
ACCOUNT_ID=$(echo "$USER_OUTPUT" | grep -o '"Account": "[0-9]*"' | cut -d'"' -f4)
if [[ -z "$ACCOUNT_ID" ]]; then
	echo "ERROR: Failed to extract account ID" | tee -a "$LOG_FILE"
	exit 1
fi

# Generate a unique role name
ROLE_NAME="SSMTutorialRole-$(openssl rand -hex 4)"

# Create trust policy for the role - FIXED: Added cloudformation.amazonaws.com
cat > trust-policy.json << 'EOF'
{
	"Version":"2012-10-17",
	"Statement": [
		{
			"Effect": "Allow",
			"Principal": {
				"Service": [
					"ssm.amazonaws.com",
					"ssm-quicksetup.amazonaws.com",
					"cloudformation.amazonaws.com"
				]
			},
			"Action": "sts:AssumeRole"
		}
	]
}
EOF

# Create the IAM role
ROLE_OUTPUT=$(log_cmd "aws iam create-role --role-name $ROLE_NAME --assume-role-policy-document file://trust-policy.json --description 'Role for Systems Manager tutorial' --output json")
ROLE_STATUS=$?
check_error "$ROLE_OUTPUT" $ROLE_STATUS "Failed to create IAM role"

# Extract the role ARN
ROLE_ARN=$(echo "$ROLE_OUTPUT" | grep -o 'arn:aws:iam::[0-9]*:role/[^"]*')
if [[ -z "$ROLE_ARN" ]]; then
	echo "ERROR: Failed to extract role ARN" | tee -a "$LOG_FILE"
	cleanup_on_error
	exit 1
fi

# Track the created role
track_resource "IAM_ROLE" "$ROLE_NAME"
aws iam tag-role --role-name "$ROLE_NAME" \
	--tags Key=project,Value=doc-smith Key=tutorial,Value=aws-systems-manager-gs

echo "Created IAM role: $ROLE_NAME" | tee -a "$LOG_FILE"
echo "Role ARN: $ROLE_ARN" | tee -a "$LOG_FILE"

# Attach the policy to the role
ATTACH_OUTPUT=$(log_cmd "aws iam attach-role-policy --role-name $ROLE_NAME --policy-arn $POLICY_ARN")
ATTACH_STATUS=$?
check_error "$ATTACH_OUTPUT" $ATTACH_STATUS "Failed to attach policy to role $ROLE_NAME"

echo "Policy attached to role: $ROLE_NAME" | tee -a "$LOG_FILE"

# Step 3: Create Systems Manager configuration using Host Management
echo ""
echo "Step 3: Creating Systems Manager configuration..."

# Generate a random identifier for the configuration name
CONFIG_NAME="SSMSetup-$(openssl rand -hex 4)"

# Create configuration file for Systems Manager setup using Host Management
cat > ssm-config.json << EOF
[
	{
		"Type": "AWSQuickSetupType-SSMHostMgmt",
		"LocalDeploymentAdministrationRoleArn": "$ROLE_ARN",
		"LocalDeploymentExecutionRoleName": "$ROLE_NAME",
		"Parameters": {
			"TargetAccounts": "$ACCOUNT_ID",
			"TargetRegions": "$CURRENT_REGION"
		}
	}
]
EOF

echo "Configuration file created:" | tee -a "$LOG_FILE"
cat ssm-config.json | tee -a "$LOG_FILE"

# Create the configuration manager
CONFIG_OUTPUT=$(log_cmd "aws ssm-quicksetup create-configuration-manager --name \"$CONFIG_NAME\" --configuration-definitions file://ssm-config.json --region $CURRENT_REGION")
CONFIG_STATUS=$?
check_error "$CONFIG_OUTPUT" $CONFIG_STATUS "Failed to create Systems Manager configuration"

# Extract the manager ARN
MANAGER_ARN=$(echo "$CONFIG_OUTPUT" | grep -o 'arn:aws:ssm-quicksetup:[^"]*')
if [[ -z "$MANAGER_ARN" ]]; then
	echo "ERROR: Failed to extract manager ARN" | tee -a "$LOG_FILE"
	exit 1
fi

# Track the created configuration manager
track_resource "SSM_CONFIG_MANAGER" "$MANAGER_ARN"

echo "Created Systems Manager configuration: $MANAGER_ARN" | tee -a "$LOG_FILE"

# Step 4: Verify the setup
echo ""
echo "Step 4: Verifying the setup..."

# Wait for the configuration to be fully deployed
echo "Waiting for the configuration to be deployed (this may take a few minutes)..."
sleep 30

# Check the configuration manager status
VERIFY_OUTPUT=$(log_cmd "aws ssm-quicksetup get-configuration-manager --manager-arn $MANAGER_ARN --region $CURRENT_REGION")
VERIFY_STATUS=$?
check_error "$VERIFY_OUTPUT" $VERIFY_STATUS "Failed to verify configuration manager"

echo "Systems Manager setup completed successfully!" | tee -a "$LOG_FILE"

# List the created resources
echo ""
echo "==========================================="
echo "CREATED RESOURCES"
echo "==========================================="
for resource in "${CREATED_RESOURCES[@]+"${CREATED_RESOURCES[@]}"}"; do
	echo "$resource"
done

# Prompt for cleanup
echo ""
echo "==========================================="
echo "CLEANUP CONFIRMATION"
echo "==========================================="
echo "Do you want to clean up all created resources? (y/n): "
CLEANUP_CHOICE="y"

if [[ "$CLEANUP_CHOICE" =~ ^[Yy]$ ]]; then
	echo "Cleaning up resources..." | tee -a "$LOG_FILE"
	cleanup_resources
	echo "Cleanup completed." | tee -a "$LOG_FILE"
else
	echo "Resources will not be cleaned up. You can manually clean them up later." | tee -a "$LOG_FILE"
fi

echo ""
echo "Script execution completed. See $LOG_FILE for details."

# Clean up temporary files
rm -f ssm-onboarding-policy.json trust-policy.json ssm-config.json 2>/dev/null || true

API 상세는 AWS CLI Command Reference의 다음 항목을 참고해요.

  • AttachRolePolicy, CreateConfigurationManager, CreatePolicy, CreateRole, DeleteConfigurationManager, DeletePolicy, DeleteRole, DetachRolePolicy, GetCallerIdentity, GetConfigurationManager

더 알아보기 (Learn more)