Sessions
중급Level 100-2002-3시간

Secure Mattermost on AWS

CloudFormation으로 보안이 강화된 Mattermost 협업 플랫폼을 AWS에 배포합니다. KMS 암호화, Secrets Manager, WAF 등 엔터프라이즈급 보안 구성을 학습합니다.

🏗️ 아키텍처 개요

이 워크샵에서 구축할 아키텍처입니다. 보안을 최우선으로 설계되었습니다.

🔒 보안 기능

  • • KMS를 통한 데이터 암호화
  • • Secrets Manager로 비밀번호 관리
  • • WAF로 웹 공격 차단
  • • Security Group으로 네트워크 격리

⚡ 주요 서비스

  • • ECS Fargate (서버리스 컨테이너)
  • • Aurora PostgreSQL Serverless v2
  • • Application Load Balancer
  • • CloudWatch (모니터링)

🔐 보안 흐름

사용자 요청이 어떻게 보안 계층을 통과하는지 보여줍니다.

📋 사전 준비

필수

AWS 계정

IAM 권한이 있는 계정이 필요합니다.

필수

VPC 및 서브넷

Public 서브넷 2개, Private 서브넷 2개가 필요합니다.

선택

SSL 인증서

HTTPS를 사용하려면 ACM 인증서가 필요합니다.

💰 예상 비용: 약 $1-2/시간 (Aurora Serverless + Fargate)
워크샵 완료 후 반드시 리소스를 정리하세요.

CloudFormation 템플릿 다운로드

전체 템플릿을 다운로드하여 사용하세요.

다운로드

단계별 학습

0

Step 0: CloudFormation 기초

Infrastructure as Code의 핵심, CloudFormation을 이해합니다.

CloudFormation이란?
AWS CloudFormation은 인프라를 코드로 정의하고 자동으로 프로비저닝하는 서비스입니다. YAML 또는 JSON 파일 하나로 복잡한 인프라를 반복 가능하게 배포할 수 있습니다.

Infrastructure as Code (IaC)

인프라를 수동으로 클릭하며 만드는 대신, 코드 파일로 정의합니다. 버전 관리, 코드 리뷰, 자동화가 가능해집니다.

🏗️ 건물을 지을 때 설계도면이 있듯이, 클라우드 인프라도 '설계도(템플릿)'를 작성합니다.

Stack

CloudFormation 템플릿으로 생성된 AWS 리소스들의 집합입니다. 스택 단위로 생성, 업데이트, 삭제가 이루어집니다.

📦 레고 블록들을 조립해서 만든 하나의 완성품이 Stack입니다.

Template 구조

CloudFormation 템플릿은 Parameters, Resources, Outputs 등의 섹션으로 구성됩니다.

AWSTemplateFormatVersion: 템플릿 버전
Description: 템플릿 설명
Parameters: 배포 시 입력받을 값들
Conditions: 조건부 리소스 생성
Resources: 실제 생성할 AWS 리소스들
Outputs: 생성 후 출력할 값들

!Ref와 !Sub

CloudFormation의 내장 함수입니다. !Ref는 다른 리소스나 파라미터를 참조하고, !Sub는 문자열 내에서 변수를 치환합니다.

!Ref VpcId → Parameters의 VpcId 값 참조
!Sub '${AWS::StackName}-alb' → 스택 이름을 포함한 문자열 생성
!GetAtt Resource.Attribute → 리소스의 속성값 가져오기
1

Step 1: 보안 기반 구성

KMS 키와 Secrets Manager로 암호화 및 비밀 관리 체계를 구축합니다.

암호화와 비밀 관리
프로덕션 환경에서는 데이터 암호화와 비밀(패스워드, API 키 등) 관리가 필수입니다. AWS KMS와 Secrets Manager가 이를 담당합니다.

AWS KMS (Key Management Service)

암호화 키를 생성하고 관리하는 서비스입니다. 데이터베이스, 로그, 스토리지 등을 암호화할 때 사용됩니다.

🔐 금고의 마스터 키를 안전하게 보관하고 관리해주는 서비스입니다.

Key Rotation

보안을 위해 암호화 키를 주기적으로 교체하는 것입니다. KMS는 자동 키 로테이션을 지원합니다.

EnableKeyRotation: true → 매년 자동으로 키 교체

AWS Secrets Manager

데이터베이스 비밀번호, API 키 등 민감한 정보를 안전하게 저장하고 자동으로 교체할 수 있습니다.

📝 비밀번호를 포스트잇에 적어두는 대신, 금고에 보관하고 필요할 때만 꺼내 쓰는 것입니다.

동적 참조 (Dynamic Reference)

CloudFormation에서 Secrets Manager의 값을 직접 참조할 수 있습니다. 비밀번호가 템플릿에 노출되지 않습니다.

{{resolve:secretsmanager:secret-id:SecretString:key}}
→ 배포 시점에 Secrets Manager에서 값을 가져옴

CloudFormation 코드

# KMS Key 생성
MattermostKMSKey:
  Type: AWS::KMS::Key
  Properties:
    Description: KMS Key for Mattermost encryption
    EnableKeyRotation: true  # 자동 키 로테이션 활성화
    KeyPolicy:
      Version: '2012-10-17'
      Statement:
        - Sid: Enable IAM User Permissions
          Effect: Allow
          Principal:
            AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root'
          Action: 'kms:*'
          Resource: '*'

# Secrets Manager로 DB 비밀번호 관리
DBSecret:
  Type: AWS::SecretsManager::Secret
  Properties:
    Name: !Sub '${AWS::StackName}-db-secret'
    GenerateSecretString:
      SecretStringTemplate: '{"username": "mmuser"}'
      GenerateStringKey: "password"
      PasswordLength: 32
      ExcludePunctuation: true  # 특수문자 제외
    KmsKeyId: !Ref MattermostKMSKey  # KMS로 암호화
2

Step 2: 네트워크 보안

Security Group으로 네트워크 접근을 제어합니다.

Security Group 설계
Security Group은 AWS의 가상 방화벽입니다. 어떤 트래픽을 허용할지 규칙을 정의하여 리소스를 보호합니다.

계층별 Security Group

ALB, ECS, RDS 각각에 별도의 Security Group을 만들어 최소 권한 원칙을 적용합니다.

🏢 건물의 각 층마다 다른 출입 카드가 필요한 것처럼, 각 계층마다 접근 권한을 분리합니다.

Ingress vs Egress

Ingress는 들어오는 트래픽, Egress는 나가는 트래픽 규칙입니다. Security Group은 기본적으로 모든 Ingress를 차단하고 모든 Egress를 허용합니다.

Security Group 체이닝

IP 대신 다른 Security Group을 소스로 지정할 수 있습니다. 이렇게 하면 IP가 바뀌어도 규칙이 유지됩니다.

ALB SG: 0.0.0.0/0에서 80, 443 허용
ECS SG: ALB SG에서 8065 허용
RDS SG: ECS SG에서 5432 허용

CloudFormation 코드

# ALB Security Group - 인터넷에서 접근 허용
ALBSecurityGroup:
  Type: AWS::EC2::SecurityGroup
  Properties:
    GroupDescription: ALB Security Group
    VpcId: !Ref VpcId
    SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 80
        ToPort: 80
        CidrIp: 0.0.0.0/0  # 모든 IP에서 HTTP 허용
      - IpProtocol: tcp
        FromPort: 443
        ToPort: 443
        CidrIp: 0.0.0.0/0  # 모든 IP에서 HTTPS 허용

# ECS Security Group - ALB에서만 접근 허용
ECSSecurityGroup:
  Type: AWS::EC2::SecurityGroup
  Properties:
    GroupDescription: ECS Security Group
    VpcId: !Ref VpcId
    SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 8065
        ToPort: 8065
        SourceSecurityGroupId: !Ref ALBSecurityGroup  # ALB SG만 허용

# RDS Security Group - ECS에서만 접근 허용
RDSSecurityGroup:
  Type: AWS::EC2::SecurityGroup
  Properties:
    GroupDescription: RDS Security Group
    VpcId: !Ref VpcId
    SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 5432
        ToPort: 5432
        SourceSecurityGroupId: !Ref ECSSecurityGroup  # ECS SG만 허용
3

Step 3: 데이터베이스 계층

Aurora PostgreSQL Serverless v2로 확장 가능한 데이터베이스를 구성합니다.

Aurora Serverless v2
Aurora Serverless v2는 워크로드에 따라 자동으로 용량을 조절하는 관리형 데이터베이스입니다. 사용한 만큼만 비용을 지불합니다.

Aurora vs RDS

Aurora는 AWS가 클라우드에 최적화하여 재설계한 데이터베이스입니다. 일반 RDS보다 최대 5배 빠르고, 자동 복제, 자동 장애 조치를 지원합니다.

Serverless v2 Scaling

ACU(Aurora Capacity Unit) 단위로 0.5~128까지 자동 확장됩니다. 트래픽이 없으면 최소 용량으로 줄어들어 비용을 절약합니다.

MinCapacity: 0.5  # 최소 0.5 ACU (약 1GB 메모리)
MaxCapacity: 2    # 최대 2 ACU (약 4GB 메모리)

Storage Encryption

StorageEncrypted: true로 설정하면 데이터가 디스크에 저장될 때 자동으로 암호화됩니다. KMS 키를 지정할 수 있습니다.

DB Subnet Group

데이터베이스가 배치될 서브넷들을 지정합니다. 고가용성을 위해 최소 2개 이상의 AZ에 걸친 Private 서브넷을 사용합니다.

CloudFormation 코드

# Aurora PostgreSQL Cluster
MattermostDBCluster:
  Type: AWS::RDS::DBCluster
  Properties:
    DBClusterIdentifier: !Sub '${AWS::StackName}-cluster'
    Engine: aurora-postgresql
    EngineVersion: '16.4'
    # Secrets Manager에서 자격 증명 가져오기
    MasterUsername: !Sub '{{resolve:secretsmanager:${DBSecret}:SecretString:username}}'
    MasterUserPassword: !Sub '{{resolve:secretsmanager:${DBSecret}:SecretString:password}}'
    DatabaseName: mattermost
    StorageEncrypted: true
    KmsKeyId: !Ref MattermostKMSKey
    DBSubnetGroupName: !Ref DBSubnetGroup
    VpcSecurityGroupIds:
      - !Ref RDSSecurityGroup
    BackupRetentionPeriod: 7  # 7일간 백업 보관
    # Serverless v2 설정
    ServerlessV2ScalingConfiguration:
      MinCapacity: 0.5
      MaxCapacity: 2

# Aurora Instance
MattermostDBInstance:
  Type: AWS::RDS::DBInstance
  Properties:
    DBInstanceClass: db.serverless  # Serverless v2
    Engine: aurora-postgresql
    DBClusterIdentifier: !Ref MattermostDBCluster
    PubliclyAccessible: false  # Private 서브넷에만 배치
4

Step 4: 로드 밸런서

Application Load Balancer로 트래픽을 분산하고 HTTPS를 처리합니다.

Application Load Balancer
ALB는 HTTP/HTTPS 트래픽을 여러 대상으로 분산하는 L7 로드 밸런서입니다. SSL 종료, 경로 기반 라우팅 등을 지원합니다.

Target Group

로드 밸런서가 트래픽을 전달할 대상들의 그룹입니다. ECS 서비스, EC2 인스턴스, Lambda 등이 대상이 될 수 있습니다.

TargetType: ip → Fargate 태스크의 IP로 직접 라우팅
HealthCheckPath: /api/v4/system/ping → 헬스체크 경로

Listener

특정 포트와 프로토콜로 들어오는 연결 요청을 처리합니다. HTTP(80), HTTPS(443) 리스너를 설정합니다.

SSL/TLS 종료

ALB에서 HTTPS를 처리하고, 백엔드로는 HTTP로 전달합니다. 인증서 관리가 중앙화되고 백엔드 부하가 줄어듭니다.

🔒 건물 입구에서 신분증 확인을 마치면, 내부에서는 자유롭게 이동하는 것과 같습니다.

HTTP → HTTPS 리다이렉트

HTTP로 접속하면 자동으로 HTTPS로 리다이렉트하여 보안을 강화합니다.

CloudFormation 코드

# Application Load Balancer
ApplicationLoadBalancer:
  Type: AWS::ElasticLoadBalancingV2::LoadBalancer
  Properties:
    Name: !Sub '${AWS::StackName}-alb'
    Scheme: internet-facing  # 인터넷에서 접근 가능
    Type: application
    SecurityGroups:
      - !Ref ALBSecurityGroup
    Subnets: !Ref PublicSubnetIds  # Public 서브넷에 배치

# Target Group
MattermostTargetGroup:
  Type: AWS::ElasticLoadBalancingV2::TargetGroup
  Properties:
    Port: 8065
    Protocol: HTTP
    VpcId: !Ref VpcId
    TargetType: ip  # Fargate용
    HealthCheckPath: /api/v4/system/ping
    HealthCheckIntervalSeconds: 30

# HTTPS Listener (SSL 인증서가 있을 때)
HTTPSListener:
  Type: AWS::ElasticLoadBalancingV2::Listener
  Condition: HasSSLCertificate
  Properties:
    DefaultActions:
      - Type: forward
        TargetGroupArn: !Ref MattermostTargetGroup
    LoadBalancerArn: !Ref ApplicationLoadBalancer
    Port: 443
    Protocol: HTTPS
    Certificates:
      - CertificateArn: !Ref SSLCertificateArn
5

Step 5: 컨테이너 서비스

ECS Fargate로 Mattermost 컨테이너를 실행합니다.

ECS Fargate
ECS Fargate는 서버 관리 없이 컨테이너를 실행하는 서버리스 컴퓨팅 엔진입니다. 인프라 관리 대신 애플리케이션에 집중할 수 있습니다.

Task Definition

컨테이너 실행에 필요한 설정을 정의합니다. 이미지, CPU/메모리, 환경변수, 포트 매핑 등을 포함합니다.

📋 요리 레시피처럼, 컨테이너를 어떻게 실행할지 상세히 적어둔 문서입니다.

Service

Task Definition을 기반으로 지정된 수의 태스크를 유지합니다. 태스크가 실패하면 자동으로 새 태스크를 시작합니다.

Task Execution Role

ECS 에이전트가 사용하는 IAM 역할입니다. ECR에서 이미지 풀, CloudWatch에 로그 전송, Secrets Manager 접근 등에 필요합니다.

Container Insights

ECS 클러스터의 메트릭과 로그를 CloudWatch에서 모니터링할 수 있게 해주는 기능입니다.

CloudFormation 코드

# ECS Cluster
MattermostCluster:
  Type: AWS::ECS::Cluster
  Properties:
    ClusterName: !Sub '${AWS::StackName}-cluster'
    ClusterSettings:
      - Name: containerInsights
        Value: enabled  # 모니터링 활성화

# Task Definition
MattermostTaskDefinition:
  Type: AWS::ECS::TaskDefinition
  Properties:
    Family: !Sub '${AWS::StackName}-task'
    NetworkMode: awsvpc  # Fargate 필수
    RequiresCompatibilities:
      - FARGATE
    Cpu: '1024'   # 1 vCPU
    Memory: '2048' # 2GB
    ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn
    ContainerDefinitions:
      - Name: mattermost
        Image: mattermost/mattermost-team-edition:latest
        PortMappings:
          - ContainerPort: 8065
        Environment:
          - Name: MM_SQLSETTINGS_DRIVERNAME
            Value: postgres
          - Name: MM_SQLSETTINGS_DATASOURCE
            Value: !Sub
              - 'postgres://${Username}:${Password}@${Host}:5432/mattermost'
              - Username: '{{resolve:secretsmanager:${DBSecret}:SecretString:username}}'
                Password: '{{resolve:secretsmanager:${DBSecret}:SecretString:password}}'
                Host: !GetAtt MattermostDBCluster.Endpoint.Address
        LogConfiguration:
          LogDriver: awslogs
          Options:
            awslogs-group: !Ref MattermostLogGroup
            awslogs-region: !Ref AWS::Region
            awslogs-stream-prefix: mattermost
6

Step 6: WAF 보호

AWS WAF로 웹 애플리케이션을 공격으로부터 보호합니다.

AWS WAF (Web Application Firewall)
WAF는 SQL Injection, XSS 등 일반적인 웹 공격으로부터 애플리케이션을 보호합니다. AWS Managed Rules를 사용하면 쉽게 보안을 강화할 수 있습니다.

Web ACL

WAF 규칙들의 집합입니다. ALB, CloudFront, API Gateway 등에 연결하여 트래픽을 필터링합니다.

AWS Managed Rules

AWS가 관리하는 사전 정의된 규칙 세트입니다. 보안 전문 지식 없이도 일반적인 위협을 차단할 수 있습니다.

AWSManagedRulesCommonRuleSet: 일반적인 웹 취약점
AWSManagedRulesKnownBadInputsRuleSet: 알려진 악성 입력
AWSManagedRulesSQLiRuleSet: SQL Injection 공격

Rule Priority

규칙은 Priority 순서대로 평가됩니다. 낮은 숫자가 먼저 평가되며, 일치하면 해당 액션을 수행합니다.

CloudFormation 코드

# WAF Web ACL
MattermostWebACL:
  Type: AWS::WAFv2::WebACL
  Properties:
    Name: !Sub '${AWS::StackName}-waf'
    Scope: REGIONAL  # ALB용
    DefaultAction:
      Allow: {}  # 기본적으로 허용
    Rules:
      # 일반적인 웹 취약점 차단
      - Name: AWSManagedRulesCommonRuleSet
        Priority: 1
        OverrideAction:
          None: {}
        Statement:
          ManagedRuleGroupStatement:
            VendorName: AWS
            Name: AWSManagedRulesCommonRuleSet
        VisibilityConfig:
          SampledRequestsEnabled: true
          CloudWatchMetricsEnabled: true
          MetricName: CommonRules
      # SQL Injection 차단
      - Name: AWSManagedRulesSQLiRuleSet
        Priority: 3
        OverrideAction:
          None: {}
        Statement:
          ManagedRuleGroupStatement:
            VendorName: AWS
            Name: AWSManagedRulesSQLiRuleSet
        VisibilityConfig:
          CloudWatchMetricsEnabled: true
          MetricName: SQLi

# WAF를 ALB에 연결
WebACLAssociation:
  Type: AWS::WAFv2::WebACLAssociation
  Properties:
    ResourceArn: !Ref ApplicationLoadBalancer
    WebACLArn: !GetAtt MattermostWebACL.Arn
7

Step 7: 배포 및 확인

CloudFormation 스택을 배포하고 Mattermost에 접속합니다.

배포 및 검증
모든 리소스가 정의되었으니 이제 배포합니다. CloudFormation은 의존성을 자동으로 파악하여 올바른 순서로 리소스를 생성합니다.

배포 전 체크리스트

배포 전에 확인해야 할 사항들입니다.

✅ VPC와 서브넷이 준비되어 있는가?
✅ Public 서브넷 2개 이상 (ALB용)
✅ Private 서브넷 2개 이상 (ECS, RDS용)
✅ (선택) SSL 인증서 ARN

배포 명령어

AWS CLI로 스택을 배포합니다.

aws cloudformation create-stack \
  --stack-name mattermost-secure \
  --template-body file://mattermost-secure.yaml \
  --parameters \
    ParameterKey=VpcId,ParameterValue=vpc-xxx \
    ParameterKey=PublicSubnetIds,ParameterValue='subnet-a,subnet-b' \
    ParameterKey=PrivateSubnetIds,ParameterValue='subnet-c,subnet-d' \
  --capabilities CAPABILITY_NAMED_IAM

배포 시간

전체 스택 배포에 약 15-20분이 소요됩니다. Aurora 클러스터 생성이 가장 오래 걸립니다.

접속 확인

Outputs의 MattermostURL로 접속하여 초기 설정을 진행합니다.

8

Step 8: 리소스 정리

워크샵 완료 후 비용 발생을 막기 위해 리소스를 삭제합니다.

리소스 정리
CloudFormation의 장점 중 하나는 스택 삭제 시 모든 리소스가 자동으로 정리된다는 것입니다.

스택 삭제

스택을 삭제하면 생성된 모든 리소스가 역순으로 삭제됩니다.

aws cloudformation delete-stack --stack-name mattermost-secure

# 또는 AWS Console에서:
CloudFormation → Stacks → mattermost-secure → Delete

삭제 확인

스택 삭제가 완료되었는지 확인합니다. DELETE_COMPLETE 상태가 되어야 합니다.

주의사항

DeletionPolicy가 Retain으로 설정된 리소스는 수동으로 삭제해야 합니다. 이 워크샵에서는 모든 리소스가 자동 삭제됩니다.

📝 정리

이 워크샵에서 배운 내용을 정리합니다.

✅ 학습한 AWS 서비스

  • • CloudFormation (IaC)
  • • KMS (암호화 키 관리)
  • • Secrets Manager (비밀 관리)
  • • ECS Fargate (서버리스 컨테이너)
  • • Aurora Serverless v2
  • • Application Load Balancer
  • • WAF (웹 방화벽)

✅ 보안 모범 사례

  • • 저장 데이터 암호화 (KMS)
  • • 비밀번호 하드코딩 금지
  • • 최소 권한 원칙 (Security Group)
  • • 계층별 네트워크 격리
  • • WAF로 웹 공격 방어
  • • 로그 중앙화 (CloudWatch)