[AWS] Systems Manager 서버 관리 자동화와 보안 강화 하기

궁금하면 500원·2024년 11월 29일

데브옵스

목록 보기
10/37

서버 관리 자동화와 보안 강화 하기

1. SSM 아키텍처 및 보안 설정

1.1 기본 인프라 설정

AWSTemplateFormatVersion: '2010-09-09'
Description: 'SSM 기본 인프라 설정'

Resources:
  SSMInstanceRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: 'sts:AssumeRole'
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore'
        - 'arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy'

  SSMInstanceProfile:
    Type: 'AWS::IAM::InstanceProfile'
    Properties:
      Roles:
        - !Ref SSMInstanceRole

  SSMLogGroup:
    Type: 'AWS::Logs::LogGroup'
    Properties:
      LogGroupName: '/ssm/automation/logs'
      RetentionInDays: 30

1.2 VPC 엔드포인트 설정

SSMVPCEndpoint:
    Type: 'AWS::EC2::VPCEndpoint'
    Properties:
      VpcId: !Ref VPC
      ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ssm'
      VpcEndpointType: Interface
      SubnetIds:
        - !Ref PrivateSubnet1
        - !Ref PrivateSubnet2
      SecurityGroupIds:
        - !Ref SSMEndpointSecurityGroup
      PrivateDnsEnabled: true

  SSMEndpointSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      GroupDescription: 'Security group for SSM VPC Endpoint'
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: !GetAtt VPC.CidrBlock

2. 자동화 파이프라인 구축

2.1 자동화 문서 생성

import boto3
import json

def create_automation_document():
    ssm = boto3.client('ssm')
    
    document_content = {
        "schemaVersion": "0.3",
        "description": "애플리케이션 배포 자동화",
        "parameters": {
            "InstanceIds": {
                "type": "StringList",
                "description": "대상 인스턴스 ID"
            },
            "S3BucketName": {
                "type": "String",
                "description": "배포 파일이 있는 S3 버킷"
            },
            "ArtifactPath": {
                "type": "String",
                "description": "배포 파일 경로"
            }
        },
        "mainSteps": [
            {
                "name": "downloadArtifact",
                "action": "aws:runShellScript",
                "inputs": {
                    "runCommand": [
                        "aws s3 cp s3://{{S3BucketName}}/{{ArtifactPath}} /tmp/",
                        "cd /tmp && unzip -o *.zip",
                        "./deploy.sh"
                    ]
                }
            },
            {
                "name": "validateDeployment",
                "action": "aws:runShellScript",
                "inputs": {
                    "runCommand": [
                        "curl -f http://localhost/health || exit 1"
                    ]
                }
            }
        ]
    }
    
    response = ssm.create_document(
        Content=json.dumps(document_content),
        Name='ApplicationDeployment',
        DocumentType='Automation',
        DocumentFormat='JSON'
    )
    return response

2.2 배포 자동화 실행

def execute_deployment():
    ssm = boto3.client('ssm')
    
    response = ssm.start_automation_execution(
        DocumentName='ApplicationDeployment',
        Parameters={
            'InstanceIds': ['i-1234567890abcdef0'],
            'S3BucketName': 'deployment-artifacts',
            'ArtifactPath': 'releases/app-1.0.0.zip'
        }
    )
    return response['AutomationExecutionId']

def check_execution_status(execution_id):
    ssm = boto3.client('ssm')
    
    response = ssm.get_automation_execution(
        AutomationExecutionId=execution_id
    )
    return response['AutomationExecution']['Status']

3. 패치 관리 자동화

3.1 패치 베이스라인 설정

def create_patch_baseline():
    ssm = boto3.client('ssm')
    
    response = ssm.create_patch_baseline(
        Name='CustomPatchBaseline',
        OperatingSystem='AMAZON_LINUX_2',
        ApprovalRules={
            'PatchRules': [
                {
                    'PatchFilterGroup': {
                        'PatchFilters': [
                            {
                                'Key': 'PRODUCT',
                                'Values': ['AmazonLinux2.0']
                            },
                            {
                                'Key': 'CLASSIFICATION',
                                'Values': ['Security', 'Bugfix']
                            },
                            {
                                'Key': 'SEVERITY',
                                'Values': ['Critical', 'Important']
                            }
                        ]
                    },
                    'ApproveAfterDays': 7,
                    'ComplianceLevel': 'CRITICAL'
                }
            ]
        },
        Description='보안 패치 자동 승인 베이스라인'
    )
    return response['BaselineId']

3.2 유지보수 기간 설정

def setup_maintenance_window():
    ssm = boto3.client('ssm')
    
    # 유지보수 기간 생성
    window_id = ssm.create_maintenance_window(
        Name='WeeklyPatchWindow',
        Schedule='cron(0 0 ? * SUN *)',  # 매주 일요일 00:00
        Duration=3,  # 3시간
        Cutoff=2,    # 2시간 전에 새 작업 중지
        AllowUnassociatedTargets=False
    )['WindowId']
    
    # 대상 등록
    target_id = ssm.register_target_with_maintenance_window(
        WindowId=window_id,
        ResourceType='INSTANCE',
        Targets=[
            {
                'Key': 'tag:Environment',
                'Values': ['Production']
            }
        ]
    )['WindowTargetId']
    
    # 패치 작업 등록
    ssm.register_task_with_maintenance_window(
        WindowId=window_id,
        TaskArn='AWS-RunPatchBaseline',
        ServiceRoleArn='arn:aws:iam::account-id:role/service-role/SSM-MaintenanceWindowRole',
        TaskType='RUN_COMMAND',
        TaskParameters={
            'Operation': {'Values': ['Install']}
        },
        MaxConcurrency='50%',
        MaxErrors='25%'
    )

4. 실전 운영 시나리오

4.1 긴급 패치 배포

def emergency_patch_deployment():
    ssm = boto3.client('ssm')
    
    # 긴급 패치 명령 실행
    response = ssm.send_command(
        Targets=[{'Key': 'tag:Environment', 'Values': ['Production']}],
        DocumentName='AWS-RunPatchBaseline',
        Parameters={
            'Operation': ['Install'],
            'SnapshotId': [''],
            'RebootOption': ['RebootIfNeeded']
        },
        TimeoutSeconds=3600,
        Comment='긴급 보안 패치 적용',
        CloudWatchOutputConfig={
            'CloudWatchLogGroupName': '/ssm/patch-management/emergency',
            'CloudWatchOutputEnabled': True
        }
    )
    
    command_id = response['Command']['CommandId']
    return command_id

4.2 롤백 자동화

def create_rollback_automation():
    ssm = boto3.client('ssm')
    
    document_content = {
        "schemaVersion": "0.3",
        "description": "애플리케이션 롤백 자동화",
        "parameters": {
            "PreviousVersion": {
                "type": "String",
                "description": "롤백할 버전"
            }
        },
        "mainSteps": [
            {
                "name": "stopApplication",
                "action": "aws:runShellScript",
                "inputs": {
                    "runCommand": [
                        "systemctl stop application"
                    ]
                }
            },
            {
                "name": "restorePreviousVersion",
                "action": "aws:runShellScript",
                "inputs": {
                    "runCommand": [
                        "aws s3 cp s3://backup/{{PreviousVersion}} /opt/application/",
                        "cd /opt/application && tar -xzf {{PreviousVersion}}"
                    ]
                }
            },
            {
                "name": "startApplication",
                "action": "aws:runShellScript",
                "inputs": {
                    "runCommand": [
                        "systemctl start application"
                    ]
                }
            }
        ]
    }
    
    ssm.create_document(
        Content=json.dumps(document_content),
        Name='ApplicationRollback',
        DocumentType='Automation',
        DocumentFormat='JSON'
    )

5. 모니터링 및 감사

5.1 CloudWatch 대시보드 설정

def setup_monitoring_dashboard():
    cloudwatch = boto3.client('cloudwatch')
    
    dashboard_body = {
        "widgets": [
            {
                "type": "metric",
                "properties": {
                    "metrics": [
                        ["AWS/SSM", "CommandSuccess", "DocumentName", "AWS-RunPatchBaseline"],
                        [".", "CommandFailed", ".", "."]
                    ],
                    "period": 300,
                    "stat": "Sum",
                    "region": "ap-northeast-2",
                    "title": "패치 명령 실행 현황"
                }
            },
            {
                "type": "metric",
                "properties": {
                    "metrics": [
                        ["AWS/SSM", "MaintenanceWindowExecution", "Status", "SUCCESS"],
                        [".", ".", ".", "FAILED"]
                    ],
                    "period": 3600,
                    "stat": "Sum",
                    "region": "ap-northeast-2",
                    "title": "유지보수 기간 실행 현황"
                }
            }
        ]
    }
    
    cloudwatch.put_dashboard(
        DashboardName='SSMOperations',
        DashboardBody=json.dumps(dashboard_body)
    )

5.2 감사 로그 설정

def setup_audit_logging():
    # CloudTrail 설정
    cloudtrail = boto3.client('cloudtrail')
    
    response = cloudtrail.create_trail(
        Name='SSMAuditTrail',
        S3BucketName='your-audit-bucket',
        IsMultiRegionTrail=True,
        EnableLogFileValidation=True
    )
    
    # CloudWatch Logs 설정
    logs = boto3.client('logs')
    
    logs.create_log_group(
        logGroupName='/aws/ssm/audit'
    )
    
    # 메트릭 필터 생성
    logs.put_metric_filter(
        logGroupName='/aws/ssm/audit',
        filterName='UnauthorizedSSMAccess',
        filterPattern='{ $.eventName = SendCommand && $.errorMessage = *UnauthorizedOperation* }',
        metricTransformations=[
            {
                'metricName': 'UnauthorizedSSMAccess',
                'metricNamespace': 'SSMAudit',
                'metricValue': '1'
            }
        ]
    )
    
    # 경보 설정
    cloudwatch = boto3.client('cloudwatch')
    
    cloudwatch.put_metric_alarm(
        AlarmName='UnauthorizedSSMAccessAlarm',
        MetricName='UnauthorizedSSMAccess',
        Namespace='SSMAudit',
        Statistic='Sum',
        Period=300,
        EvaluationPeriods=1,
        Threshold=1,
        ComparisonOperator='GreaterThanOrEqualToThreshold',
        AlarmActions=['arn:aws:sns:region:account-id:security-alerts']
    )

결론

AWS Systems Manager는 서버 관리와 자동화를 위한 강력한 도구입니다.
적절한 설정과 자동화를 통해 다음과 같은 이점을 얻을 수 있습니다.

1. 보안 강화: VPC 엔드포인트와 최소 권한 원칙 적용
2. 운영 자동화: 패치 관리와 배포 자동화
3. 감사 및 모니터링: 실시간 모니터링과 감사 로그 관리
4. 장애 대응: 롤백 자동화와 긴급 패치 배포

이러한 기능들을 적절히 활용하면 안전하고 효율적인 서버 관리가 가능합니다.

profile
에러가 나도 괜찮아 — 그건 내가 배우고 있다는 증거야.

0개의 댓글