CloudFormation으로 AWS Directory Service 생성해 보기

CloudFormation으로 AWS Directory Service를 생성해 보는 과정을 정리해 봤습니다.
2022.07.24

안녕하세요 클래스메소드 김재욱(Kim Jaewook) 입니다. 이번에는 CloudFormation으로 AWS Directory Service를 생성해 보는 과정을 정리해 봤습니다.

작업 순서는 다음과 같습니다.

  • Parameter Store 생성(Directory Service의 비밀번호를 저장하기 위해서 사용)
  • CloudFormation으로 VPC 생성
  • CloudFormation으로 Directory Service 생성
  • CloudFormation으로 DHCP Option Set 생성

매니지먼트 콘솔에서 Directory Service를 생성하는 방법은 아래 블로그를 참고해 주세요.

Parameter store 생성

Parameter Store로 들어온 다음「파라미터 생성」버튼을 클릭합니다.

Parameter의 이름을 적은 다음, 유형은「보안 문자열」을 선택하고, KMS 키 소스는「내 현재 계정」을 선택합니다.

마지막으로「값」에 Directory Service의 비밀번호를 입력합니다.

CloudFormation으로 VPC 생성

AWSTemplateFormatVersion: "2010-09-09"
Description: VPC Network set
Metadata: 
  "AWS::CloudFormation::Interface": 
    ParameterGroups: 
      - Label: 
          default: "Network Configuration"
        Parameters: 
          - VPCCIDR
          - PublicSubnetACIDR
          - PublicSubnetCCIDR
          - PrivateSubnetACIDR
          - PrivateSubnetCCIDR
    ParameterLabels: 
      VPCCIDR: 
        default: "VPC CIDR"
      PublicSubnetACIDR: 
        default: "PublicSubnetA CIDR"
      PublicSubnetCCIDR: 
        default: "PublicSubnetC CIDR"
      PrivateSubnetACIDR: 
        default: "PrivateSubnetA CIDR"
      PrivateSubnetCCIDR: 
        default: "PrivateSubnetC CIDR"
#-------------------------------------------------------------------
#Input VPC, Subnet Parameters
#-------------------------------------------------------------------
Parameters:
  VPCCIDR:
    Type: String
    Default: "10.0.0.0/16"

  PublicSubnetACIDR:
    Type: String
    Default: "10.0.0.0/24"

  PublicSubnetCCIDR:
    Type: String
    Default: "10.0.64.0/24"

  PrivateSubnetACIDR:
    Type: String
    Default: "10.0.128.0/24"

  PrivateSubnetCCIDR:
    Type: String
    Default: "10.0.192.0/24"
#-------------------------------------------------------------------
#Set VPC, InternetGateway, Subnet
#-------------------------------------------------------------------
Resources:
  VPC: 
    Type: "AWS::EC2::VPC"
    Properties: 
      CidrBlock: !Ref VPCCIDR
      EnableDnsSupport: "true"
      EnableDnsHostnames: "true"
      InstanceTenancy: default
      Tags: 
        - Key: Name
          Value: !Sub "test-vpc"
  InternetGateway: 
    Type: "AWS::EC2::InternetGateway"
    Properties: 
      Tags: 
        - Key: Name
          Value: !Sub "test-igw"
  InternetGatewayAttachment: 
    Type: "AWS::EC2::VPCGatewayAttachment"
    Properties: 
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref VPC
  PublicSubnetA: 
    Type: "AWS::EC2::Subnet"
    Properties: 
      AvailabilityZone: "ap-northeast-1a"
      CidrBlock: !Ref PublicSubnetACIDR
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub "test-front-subnet-1a"
  PublicSubnetC: 
    Type: "AWS::EC2::Subnet"
    Properties: 
      AvailabilityZone: "ap-northeast-1c"
      CidrBlock: !Ref PublicSubnetCCIDR
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub "test-front-subnet-1c"
  PrivateSubnetA: 
    Type: "AWS::EC2::Subnet"
    Properties: 
      AvailabilityZone: "ap-northeast-1a"
      CidrBlock: !Ref PrivateSubnetACIDR
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub "test-application-subnet-1a"
  PrivateSubnetC: 
    Type: "AWS::EC2::Subnet"
    Properties: 
      AvailabilityZone: "ap-northeast-1c"
      CidrBlock: !Ref PrivateSubnetCCIDR
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub "test-application-subnet-1c"
#-------------------------------------------------------------------
#Route Tables
#-------------------------------------------------------------------
  FRONTRTB : 
    Type: "AWS::EC2::RouteTable"
    Properties: 
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub "test-front-rtb"
  APPRTB1A: 
    Type: "AWS::EC2::RouteTable"
    Properties: 
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub "test-application-rtb-1a"
  APPRTB1C: 
    Type: "AWS::EC2::RouteTable"
    Properties: 
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub "test-application-rtb-1c"
  FRONTRTBroute: 
    Type: "AWS::EC2::Route"
    Properties: 
      RouteTableId: !Ref FRONTRTB
      DestinationCidrBlock: "0.0.0.0/0"
      GatewayId: !Ref InternetGateway
#-------------------------------------------------------------------
#Route Tables Subnet Association
#-------------------------------------------------------------------
  FRONTRTBAssociation: 
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties: 
      SubnetId: !Ref PublicSubnetA
      RouteTableId: !Ref FRONTRTB
  FRONTRTB2Association: 
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties: 
      SubnetId: !Ref PublicSubnetC
      RouteTableId: !Ref FRONTRTB
  APPRTB1AAssociation: 
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties: 
      SubnetId: !Ref PrivateSubnetA
      RouteTableId: !Ref APPRTB1A
  APPRTB1CAssociation: 
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties: 
      SubnetId: !Ref PrivateSubnetC
      RouteTableId: !Ref APPRTB1C
#-------------------------------------------------------------------
#OutPut
#-------------------------------------------------------------------
Outputs:
# VPC
  VPC:
    Value: !Ref VPC
    Export:
      Name: !Sub "test-vpc"

  VPCCIDR:
    Value: !Ref VPCCIDR
    Export:
      Name: !Sub "test-vpc-cidr"
# Subnet
  PublicSubnetA:
    Value: !Ref PublicSubnetA
    Export:
      Name: !Sub "test-front-subnet-1a"

  PublicSubnetACIDR:
    Value: !Ref PublicSubnetACIDR
    Export:
      Name: !Sub "test-front-subnet-1a-cidr"

  PublicSubnetC:
    Value: !Ref PublicSubnetC
    Export:
      Name: !Sub "test-front-subnet-1c"

  PublicSubnetCCIDR:
    Value: !Ref PublicSubnetCCIDR
    Export:
      Name: !Sub "test-front-subnet-1c-cidr"

  PrivateSubnetA:
    Value: !Ref PrivateSubnetA
    Export:
      Name: !Sub "test-application-subnet-1a"

  PrivateSubnetACIDR:
    Value: !Ref PrivateSubnetACIDR
    Export:
      Name: !Sub "test-application-subnet-1a-cidr"

  PrivateSubnetC:
    Value: !Ref PrivateSubnetC
    Export:
      Name: !Sub "test-application-subnet-1c"

  PrivateSubnetCCIDR:
    Value: !Ref PrivateSubnetCCIDR
    Export:
      Name: !Sub "test-application-subnet-1c-cidr"

# Route
  FRONTRTB:
    Value: !Ref FRONTRTB
    Export:
      Name: !Sub "test-front-rtb"

  APPRTB1A:
    Value: !Ref APPRTB1A
    Export:
      Name: !Sub "test-application-rtb-1a"

  APPRTB1C:
    Value: !Ref APPRTB1C
    Export:
      Name: !Sub "test-application-rtb-1c"

VPC를 생성합니다. NAT Gateway는 생성을 안했지만, 필요하다면 NAT Gateway도 추가로 생성합니다.

Directory Service, DHCP Option Set 생성

AWSTemplateFormatVersion: "2010-09-09"
Description: Directory Service, DHCP Option set
Metadata: 
  "AWS::CloudFormation::Interface": 
    ParameterGroups: 
      - Label: 
          default: "Directory Service Configuration"
        Parameters: 
          - ADdnsName
          - ADnetBiosName
          - ADEdition
    ParameterLabels: 
      ADdnsName: 
        default: "Directory Service DNS Name"
      ADnetBiosName: 
        default: "Directory Service NetBios Name"
      ADEdition: 
        default: "Directory Service Edition"

#-------------------------------------------------------------------
#Input Directory Service Parameters
#-------------------------------------------------------------------
Parameters:
  ADdnsName:
    Type: String
    Default: "corp.example.com"

  ADnetBiosName:
    Type: String
    Default: "AWS"

  ADEdition:
    Type: String
    Default: "Standard"

#-------------------------------------------------------------------
#Create Directory Service
#-------------------------------------------------------------------
Resources:
  myDirectory: 
    Type: AWS::DirectoryService::MicrosoftAD
    Properties: 
      Name:
        Ref : ADdnsName
      Password: '{{resolve:ssm-secure:test-ad-password:1}}'
      ShortName: 
        Ref: ADnetBiosName
      Edition:
        Ref : ADEdition
      VpcSettings: 
        SubnetIds: 
          - { "Fn::ImportValue": !Sub "test-application-subnet-1a" }
          - { "Fn::ImportValue": !Sub "test-application-subnet-1c" }
        VpcId: { "Fn::ImportValue": !Sub "test-vpc" }

#-------------------------------------------------------------------
#Create DHCP Option set
#-------------------------------------------------------------------
  myDHCPOptionSet:
      Type: AWS::EC2::DHCPOptions
      Properties: 
        DomainName: !Ref ADdnsName
        DomainNameServers:
          - !Select [ '0', !GetAtt myDirectory.DnsIpAddresses ]
          - !Select [ '1', !GetAtt myDirectory.DnsIpAddresses ]
        Tags: 
          - Key: Name
            Value: test-dhcp-ad

  myDHCPOptionAssociation:
    Type: AWS::EC2::VPCDHCPOptionsAssociation
    Properties: 
      DhcpOptionsId: !Ref myDHCPOptionSet
      VpcId: { "Fn::ImportValue": !Sub "test-vpc" }


#-------------------------------------------------------------------
#OutPut
#-------------------------------------------------------------------
Outputs:
  DirectoryID:
    Description: Directory Service ID
    Value: !Ref myDirectory
    Export:
      Name: !Sub "myDirectory-id"
  PrimaryDNS:
    Description: Directory Service DNS IPs
    Value: !Select [ '0', !GetAtt myDirectory.DnsIpAddresses ]
    Export:
      Name: !Sub "myDirectory-primary-dns"
  SecondaryDNS:
    Description: Directory Service DNS IPs
    Value: !Select [ '1', !GetAtt myDirectory.DnsIpAddresses ]
    Export:
      Name: !Sub "myDirectory-secondary-dns"
  myDHCPOptionSet:
    Description: DHCPOptionSet ID
    Value: !Ref myDHCPOptionSet
    Export:
      Name: !Sub "myDHCPOptionSet-id"

Directory Service와 DHCP Option Set을 생성합니다.

Parameter Store에 저장한 Directory Service의 비밀번호는 다음과 같이 불러올 수 있습니다.

  • '{{resolve:ssm-secure:test-ad-password:1}}'

생성한 리소스 확인

먼저 Stack에서 출력 값들을 보면 문제없이 값들이 출력되고 있는 것을 확인할 수 있습니다.

DHCP를 확인해 보면 문제 없이 도메인과 도메인 이름 서버가 설정된 것을 볼 수 있습니다.

VPC에 생성한 DHCP가 설정 되어 있는지 확인 해 보면 test-dhcp-ad가 문제 없이 설정된 것을 확인할 수 있습니다.

마지막으로 Directory Service를 확인해 보면 CloudFormation에서 설정한 값과 동일하게 생성된 것을 확인할 수 있습니다.

EC2 Windows에 AD를 등록하는 방법에 대해서는 아래 블로그를 참고해 주세요.

본 블로그 게시글을 보시고 문의 사항이 있으신 분들은 클래스메소드코리아 (info@classmethod.kr)로 연락 주시면 빠른 시일 내 담당자가 회신 드릴 수 있도록 하겠습니다 !