[파이널 프로젝트] Route53을 이용해 도메인 설정 & TTL 설정

신현식·2023년 3월 24일
0

구름_Kubernetes

목록 보기
18/25
post-thumbnail

Route53

Route53과 External DNS를 이용하여 외부에서 클라이언트가 IP주소나 복잡한 로드밸런서의 주소를 입력하는 것이 아니라, 우리가 흔히 보는 도메인을 입력하여 서비스에 접근할 수 있도록 한다.

  • 과정
    1 . AWS Route53을 이용하여 도메인을 등록하고 호스팅 영역을 설정한다
    2 . EKS에서 External DNS을 이용하여 Route 53을 통해 등록한 도메인과 연결한다.

External DNS란?

External DNS는 kubernetes dns(kube-dns)와 상반되는 개념으로 내부 도메인서버가 아닌 Public한 도메인서버(AWS Route53, GCP DNS 등)를 사용하여 쿠버네티스의 리소스를 쿼리할 수 있게 해주는 오픈소스 솔루션이다.
External DNS를 사용하면 public도메인 서버가 무엇이든 상관없이 쿠버네티스 리소스를 통해서 DNS레코드를 동적으로 관리 할 수 있다.

External DNS 배포 참조 1 - AWS공식문서
External DNS 배포 참조 2


1 Router53 도메인 등록
AWS콘솔의 Route53에 들어가 도메인 등록 클릭 후 원하는 도메인을 검색한다. 해당 도메인이 사용 가능하다면 구입한다.
📢 AWS Router53 도메인 이름 등록하는 방법

  • 도메인을 구입했다면 자동으로 호스팅영역이 설정될 것이고, 기본적으로 SOA, NS 레코드가 생성되어 있는 것을 알 수 있다.

    호스팅영역은 특정 도메인과 하위 도메인의 트래픽을 라우팅하는 방식에 대한 정보를 나타낸다. 쉽게 말해, DNS서버에 도메인이 입력되었을 때 DNS쿼리로 해당 도메인에 대한 결과를 얻게 되는데 , 이 결과에 대한 종류라고 생각하면 된다.

2 IAM 정책 생성
쿠버네티스 서비스 계정에 IAM 역할을 사용하려면 OIDC 공급자가 필요하다. IAM OIDC 자격 증명 공급자를 생성한다.

  • 하지만 우리는 클러스터 배포과정에서 이미 OIDC를 공급했기 때문에 굳이 다시 생성할 필요가 없다.
eksctl utils associate-iam-oidc-provider --cluster {cluster name} --approve
  • External DNS용도의 구분된 namespace를 생성한다.
kubectl create namespace external-dns
  • External DNS가 Route53을 제어할 수 있도록 iam정책을 작성하고 생성한다.
    • AWS 콘솔에서 IAM정책에 가보면 생성되어 있는 것을 확인가능
vi AllowExternalDNSUpdates.json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "route53:ChangeResourceRecordSets"
      ],
      "Resource": [
        "arn:aws:route53:::hostedzone/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "route53:ListHostedZones",
        "route53:ListResourceRecordSets"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}

# 생성한 json파일로 IAM Policy를 생성
aws iam create-policy --policy-name AllowExternalDNSUpdates --policy-document file://AllowExternalDNSUpdates.json

3 IAM 역할을 생성하고 Kubernetes 서비스 계정과 연결

  • IAM정책을 붙인 IAM롤(= iamserviceaccount)를 생성한다.
  • --override-existing-serviceaccounts 명령어는 기존의 서비스 계정에 영향을 줄 수 있으므로 제거
  • AWS콘솔에서 확인가능 [IAM -> 역할 -> 이름 검색]
eksctl create iamserviceaccount --name external-dns \
--namespace external-dns \
--cluster finalproject \
--attach-policy-arn arn:aws:iam::<Account ID>:policy/<IAM정책이름> \
--approve \
--role-name route53_external_dns

주의사항
클러스터 노드 IAM Role에 Route53 접근권한이 설정되지 않는 경우 배포가 되지 않는다. 확인해보고 적용이 안되었으면 IAM Role 콘솔에서 직접 적용해야한다.

💡 AWS Identity and Access Management(IAM)
IAM은 AWS 리소스에 대한 액세스를 안전하게 제어할 수 있는 웹 서비스입니다. IAM을 사용하면 사용자가 액세스할 수 있는 AWS 리소스를 제어하는 권한을 중앙에서 관리할 수 있습니다. IAM을 사용하여 리소스를 사용하도록 인증(로그인) 및 권한 부여(권한 있음)된 대상을 제어합니다.

4 EKS에 External-DNS 파드 배포
EKS는 파드를 띄워서 External-DNS를 통해 도메인과 연결한다.

  • RBAC이 활성화 되어있다는 전제하에 ClusterRole과 ClusterRoleBinding을 이용한다.
# RBAC 활성여부 확인
kubectl api-versions | grep rbac.authorization.k8s.io 

# External-DNS 파드용 파일 작성
vi external-dns.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: external-dns
  namespace: external-dns
  # If you're using Amazon EKS with IAM Roles for Service Accounts, specify the following annotation.
  # Otherwise, you may safely omit it.
  annotations:
    # Substitute your account ID and IAM service role name below.
    eks.amazonaws.com/role-arn: arn:aws:iam::<Account ID>:role/<생성한 Role> 
---

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: external-dns
  namespace: external-dns
rules:
- apiGroups: [""]
  resources: ["services","endpoints","pods"]
  verbs: ["get","watch","list"]
- apiGroups: ["extensions","networking.k8s.io"]
  resources: ["ingresses"]
  verbs: ["get","watch","list"]
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["list","watch"]

---

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: external-dns-viewer
  namespace: external-dns
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: external-dns
subjects:
- kind: ServiceAccount
  name: external-dns
  namespace: external-dns

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: external-dns
  namespace: external-dns
spec:
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: external-dns
  template:
    metadata:
      labels:
        app: external-dns
    spec:
      serviceAccountName: external-dns
      containers:
      - name: external-dns
        image: k8s.gcr.io/external-dns/external-dns:v0.10.2 # external-dns를 가능하게 하는 파드를 생성하는 이미지, 버전이 지속적으로 바뀌기때문에 고려해서 지정 
        args:
        - --source=service
        - --source=ingress
        - --domain-filter= # 등록한 도메인 입력 
        - --provider=aws
        - --policy=upsert-only 
        - --aws-zone-type=public # only look at public hosted zones (valid values are public, private or no value for both)
        - --registry=txt 
        - --txt-owner-id= # Route53 호스팅영역 ID입력
      securityContext:
        fsGroup: 65534 # For ExternalDNS to be able to read Kubernetes and AWS token files

# yaml파일 api-server에 전송
kubectl create -f external-dns.yaml 
  • policy의 경우 Route53에서 레코드 업데이트를 제어하는 정책, Sync정책은 삭제권한이 존재하기 때문에 사용에 주의

    • upsert-only: 생성, 업데이트
    • sync: 생성, 업데이트, 삭제
    • create-only: 생성
  • 서비스계정은 처음에는 이미 존재하기때문에 만들어지지 않는데, 이것은 3번에서 IAM롤로 이미 생성해놨기 때문이다.
    -> 이미 IAM롤로 서비스계정을 만들어놨는데도 yaml파일에 굳이 다시 IAM롤이 부여된 서비스계정을 다시 만드는 이유는 나중에 혹시라도 서비스계정이 삭제되었을때 일일이 다시 3번처럼 서비스 계정을 만드는 것이 아니라, yaml파일 실행 한번으로 External-DNS에 필요한 서비스계정 포함 총 4가지 리소스를 쉽게 배포하기 위해서다.

  • 또한 해당 yaml파일을 ArgoCD와 연동중인 Git에 Push하여 ArgoCD로 배포할까 생각했지만, 생각해보니 굳이 DNS서버와 연결하는 External-DNS파드를 외부에 노출시킬 필요가 없고, 서비스계정, RBAC 코드도 다 노출되기 때문에 그냥 로컬에서 수동으로 클러스터에 배포하였다.

5 Ingress수정 및 결과 테스트

  • 결과적으로 외부 사용자가 도메인을 입력하여 접속하는 것은 프론트엔드로 구성된 웹페이지이게 프론트엔드 파드를 외부에 노출시키는 Ingress(=ALB)를 수정한다.
  • 백엔드 파드를 외부에 노출시키는 Ingress(=ALB)는 도메인과 연결할 필요없이 추후에 프론트엔드와 연결한다.

한마디로, External-DNS를 가능하게 하는 파드를 띄웠고 이를 통해 프론트엔드 파드를 외부에 노출시키는 Ingress(=ALB)를 도메인에 연결한다. 따라서 아래와 같이 수정한다.

vi front-ing.yaml

. . .
spec:
  rules:
  - host: "k8s-finalproject.com" # 도메인 추가 
    http:
. . .

# external-dns의 로그를 확인해서 레코드가 정상적으로 생성되는지 확인
kubectl logs -f {external-dns pod name} -n external-dns

구매한 도메인을 브라우저에 입력했을 때 정상적으로 프론트엔드로 구성된 웹페이지가 나타나는 것을 볼 수 있다.

HTTPS 통신

지금까지 도메인을 입력하여 Frontend로 구성된 웹페이지에 접속하는 것은 http 프로토콜을 이용한 통신이였다. 하지만 http통신은 평문통신이기 때문에 보안에 취약하다. 따라서 https통신을 구현할 것이다.

1 TLS인증서 발급받기
이전에 Route53으로 구매한 도메인에 대해 유효한 TLS인증서를 발급받아야한다.

  • 퍼블릭 AWS Certificate Manager(ACM)을 이용하여 TLS를 발급받는다.
    📢 ACM인증서 발급받기 참고 - 공식문서

    • 인증방식은 이메일 검증을 선택했고, 좀 기다리면 이메일에 인증링크가 온다. 해당 링크를 승인하면 나의 도메인에 대한 유효한 TLS인증서가 발급된다.
    • 발급된 인증서의 arn을 식별해둔다.

2 . Frontend - Ingress 수정
주석부분에서 TLS인증서의 arn을 추가하고, listen-port로 80/http, 443/https 포트를 추가함으로써 외부사용자의 80/http OR 443/https 포트를 통한 요청을 둘다 허용한다.
이때 tls-redirect를 443으로 지정함으로써 80/http요청에 대해 443/https로 리디렉션한다.

vi front-ing.yaml

. . .
annotations:
. . .
  alb.ingress.kubernetes.io/certificate-arn: # 위에서 식별한 인증서의 arn값 입력
  alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
  alb.ingress.kubernetes.io/tls-redirect: '443'
. . .   

📢 TLS인증서를 이용한 HTTPS연결 활성화 참조 - 공식문서

profile
전공 소개

0개의 댓글