Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.

Terraform으로 ACM 인증서 생성하기

AWS의 ACM(AWS Certificate Manager)은 AWS에서 SSL/TLS 인증서를 무료로 사용할 수 있는 서비스다. 요즘은 Let's Encrypt가 있지만, 일반적으로 SSL/TLS 인증서 비용이 꽤 크기 때문에 서비스를 AWS에서 제공하고 있다면 ACM을 이용하지 않을 이유가 없다.

내 기억이 맞는다면 예전에는 Terraform으로 ACM을 이용할 때 Data Source로만 사용할 수 있었다. 즉, AWS 웹 관리 콘솔에서 ACM 인증서를 발급하고 승인한 뒤에 이를 aws_acm_certificate 데이터 소스로 가져와서 CloudFront나 ELB 등에 연결해서 사용했다.

그러다가 최근에 AWS를 사용하다 보니 ACM을 Terrafrom에서 직접 생성할 수 있게 된 것을 발견했다.

resource "aws_acm_certificate" "demo_sideeffect_kr" {
  domain_name       = "demo.sideeffect.kr"
  validation_method = "EMAIL"
}

다른 리소스처럼 aws_acm_certificate를 이용해서 생성할 수 있다. 인증서는 승인을 해야 하는데 도메인으로 승인하거나 이메일에서 승인할 수 있다. 도메인 승인은 개인적으로 더 복잡하다고 느껴서 여기서는 이메일로 승인하는 방법을 사용했다.

ACM은 리전 내에서 생성되지만 CloudFront에서 사용하려면 버지니아 북부(us-east-1)에 인증서를 생성해야 한다. 이미 Terraform에서 사용하는 리전이 있다면 아래처럼 버지니아 북부를 위한 프로바이더를 추가하고 alias를 추가해야 한다.

provider "aws" {
  version = "~> 1.33"
  region  = "ap-northeast-1"
}

provider "aws" {
  alias   = "virginia"
  region  = "us-east-1"
}

이렇게 생성한 aliasprovider로 지정하면 이 ACM은 지정한 리전에 생성되게 된다.

resource "aws_acm_certificate" "demo_sideeffect_kr" {
  provider          = "aws.virginia"

  domain_name       = "demo.sideeffect.kr"
  validation_method = "EMAIL"
}

terraform apply로 적용하고 나면 아래처럼 인증서의 승인을 요청하는 이메일이 등록된 이메일로 전달된다.

ACM 승인 메일

이메일을 승인하면 인증서 발급이 완료된다. 이렇게 생성한 인증서를 aws_acm_certificate.demo_sideeffect_kr.id 등으로 가져와서 사용할 수 있다. 문서에 따르면 EMAIL을 승인 대신 DOMAIN 승인을 이용하면 Terraform을 이용해서 바로 Route53 레코드를 생성해서 승인할 수도 있지만, 개인적으로 Route53에 불필요한 레코드가 생성되는 걸 좋아하지 않는 편이라 그냥 이메일 승인을 사용하고 있다.

ACM과 관련해서 aws_acm_certificate_validation도 있는데 이는 해당 ACM이 승인되는지 기다리는 역할을 한다. 도메인 인증을 사용한다면 레코드를 생성하고 DOMAIN으로 승인되는 과정을 확인하게 되겠지만 EMAIL 승인을 사용한다면 메일에서 확인할 때까지 그냥 계속 기다리게 된다. 그래서 EMAIL 승인을 사용하는 경우에는 굳이 aws_acm_certificate_validation를 사용할 필요 없이 aws_acm_certificate만 사용하고 이메일로 승인하는 것으로 충분해 보인다.

2018/08/28 02:08 2018/08/28 02:08

Hylyard로 Spinnaker를 Kubernetes에 설치하기

전에 CD(Continuous Delivery) 도구인 Spinnaker를 테스트해 보려고 Docker for Mac에서 kubernetes를 사용해 봤는데 본격적으로 사용해 보려고 하니 클라우드에서 테스트를 해보고 싶었다. 이전에는 Spinnaker가 목적이 아니라 Chaos Monkey가 목적이라서 로컬에서 테스트했지만, Spinnaker 자체를 보려고 하니 실제 프로덕션에서는 어떻게 동작하는 지도 관심이 갔다.

처음에는 데모/평가용 설치를 해보려고 했지만 Google Cloud Launcher로 실행해 보려고 했지만, GCP를 잘 몰라서 그런지 제대로 실행 안 되는 문제를 도저히 해결할 수 없어서 실제 프로덕션 환경과 똑같이 설치하는 쪽으로 넘어갔다.

Spinnaker 관리 도구 Halyard 설치하기

Spinnaker를 프로덕션 환경에서 설치하려면 Spinnaker를 관리하는 Halyard라는 도구를 설치해야 한다. 문서에 따르면 로컬에 설치하거나 Docker를 이용해서 사용할 수 있는 것 같은데 Docker를 이용하면 생각지 못한 문제를 겪을 것 같아서 나는 로컬에 직접 Halyard를 설치했다. 참고로 Halyard는 Linux와 macOS에만 설치 가능한 것으로 보인다.

먼저 Hylyard 설치 스크립트를 다운 받는다.

$ curl -O https://raw.githubusercontent.com/spinnaker/halyard/master/install/macos/InstallHalyard.sh
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  4420  100  4420    0     0  11282      0 --:--:-- --:--:-- --:--:-- 11304

다운받은 스크립트를 실행한다. 참고로 Hylyard를 설치하려면 Java 8 이상이 필요하고 설치되어 있지 않다면 Java >=8 not yet installed - please install java >=8. 오류가 발생한다.

$ $ sudo bash InstallHalyard.sh
Halyard version will be stable
Halconfig will be stored at /Users/jeonghunbyeon/.hal/config
Uninstall script is located at /Users/jeonghunbyeon/.hal/uninstall.sh
Java is already installed & at the right version
~/bin/installhalyard.fbmx ~/bin
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  186M  100  186M    0     0  19.7M      0  0:00:09  0:00:09 --:--:-- 19.8M
x halyard/
x halyard/config/
x halyard/config/halyard.yml
x halyard/lib/
x halyard/lib/aws-java-sdk-lex-1.11.251.jar
... 중략 ...
x halyard/bin/hal.bat
x halyard/bin/halyard.bat
x halyard/bin/hal
x halyard/bin/halyard
x hal
x update-halyard
~/bin
The halyard daemon isn't running yet... starting it manually...
1.6.0-20180806143444

제대로 설치되었는지 다음 명령어로 확인해 볼 수 있다.

$ hal -v
1.6.0-20180806143444


GKE에 Spinnaker 설치하기

Halyard가 Spinnaker의 생명주기를 관리해 주기 때문에 다양한 환경에 설치할 수 있다.(Spinnaker가 Kubernetes에 맞춰진 도구는 아니다.) 문서를 보면 EKS, GKE 뿐만 아니라 DC/OS, Google App Engine, AWS 등 다양한 환경에 설치할 수 있고 나 같은 경우는 Kubernetes와 사용해 보려는 것이 목적이었기 때문에 Kubernetes Provider V2 (Manifest Based)를 선택했다. 어차피 Kubernetes와 연동해서 사용하면 Kubernetes가 어디에 설치되어 있는가는 큰 상관이 없으므로 AWS EKS나 Google GKE인가에 상관없이 "Kubernetes (legacy provider)"와 "Kubernetes Provider V2 (Manifest Based)"로만 나뉘게 된다.

Spinnaker를 Kubernests와 함께 사용할 만한지 확인해 보려는 게 목적이었으므로 GKE에 Kubernetes 클러스터를 생성하고 Spinnaker 설치에 들어갔다.

설치한 GKE 클러스터를 kubectl이 컨텍스트로 사용하도록 gcloud로 인증정보를 가져온다.

$ gcloud container clusters get-credentials spinnaker-test
Fetching cluster endpoint and auth data.
kubeconfig entry generated for spinnaker-test.

kubectl로 확인해도 같은 컨텍스트를 보고 있는 걸 알 수 있다.

$ kubectl config get-contexts
CURRENT   NAME                                                 CLUSTER                                              AUTHINFO                                             NAMESPACE
          docker-for-desktop                                   docker-for-desktop-cluster                           docker-for-desktop
*         gke_devenv-205606_asia-northeast1-a_spinnaker-test   gke_devenv-205606_asia-northeast1-a_spinnaker-test   gke_devenv-205606_asia-northeast1-a_spinnaker-test
          tf_gke_devenv-205606_asia-northeast1-a_sebak-test    tf_gke_devenv-205606_asia-northeast1-a_sebak-test    tf_gke_devenv-205606_asia-northeast1-a_sebak-test

이후 설치 과정을 따라가다 보니 spinnaker라는 네임스페이스를 사용하는 것 같아서 네임스페이스를 새로 생성했다. 이는 실제로 운영하면서 다시 확인해 봐야 한다. 네임스페이스를 만들려고 ns.json 파일을 다음과 같이 만든다.

{
  "kind": "Namespace",
  "apiVersion": "v1",
  "metadata": {
    "name": "spinnaker",
    "labels": {
      "name": "spinnaker"
    }
  }
}

정의한 네임스페이스를 Kubernetes에 생성한다.

$ kubectl create -f ns.json
namespace "spinnaker" created

Kubernetes 프로바이더를 활성화한다.

$ hal config provider kubernetes enable
The halyard daemon isn't running yet... starting it manually...
+ Get current deployment
  Success
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.fasterxml.jackson.databind.util.ClassUtil (file:/opt/halyard/lib/jackson-databind-2.8.8.jar) to constructor java.lang.Void()
WARNING: Please consider reporting this to the maintainers of com.fasterxml.jackson.databind.util.ClassUtil
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
+ Edit the kubernetes provider
  Success
+ Successfully enabled kubernetes

k8s-account라는 이름으로 어카운트를 설정한다.

$ hal config provider kubernetes account add k8s-account \
     --provider-version v2 \
     --context $(kubectl config current-context)
+ Get current deployment
  Success
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.fasterxml.jackson.databind.util.ClassUtil (file:/opt/halyard/lib/jackson-databind-2.8.8.jar) to constructor java.lang.Void()
WARNING: Please consider reporting this to the maintainers of com.fasterxml.jackson.databind.util.ClassUtil
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
+ Add the k8s-account account
  Success
+ Successfully added account k8s-account for provider
  kubernetes.

아티팩트를 활성화한다.

$ hal config features edit --artifacts true
+ Get current deployment
  Success
+ Get features
  Success
- No changes supplied.

이제 환경을 선택하라고 나오는데 환경으로는 "Distributed installation", "Local installations", "Local git installations"가 있다. 나같은 경우는 Kubernetes에 설치할 것이므로 "Distributed installation"를 선택했다. 환경설정을 위해 ACCOUNT 환경변수를 설정하고 아래 명령어를 실행한다.

$ ACCOUNT=k8s-account

$  hal config deploy edit --type distributed --account-name $ACCOUNT
+ Get current deployment
  Success
+ Get the deployment environment
  Success
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.fasterxml.jackson.databind.util.ClassUtil (file:/opt/halyard/lib/jackson-databind-2.8.8.jar) to constructor java.lang.Void()
WARNING: Please consider reporting this to the maintainers of com.fasterxml.jackson.databind.util.ClassUtil
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
+ Edit the deployment environment
  Success
+ Successfully updated your deployment environment.

다음은 Spinnaker의 설정 등을 관리할 스토리지를 설정해 주어야 한다. AWS S3, Redis, Google Cloud Storage(GCS) 등을 선택할 수 있는데 어차피 GKE로 설정하고 있으므로 GCS를 선택했다.

GCS 스토리지를 설정한다.

$ PROJECT=$(gcloud info --format='value(config.project)')
$ BUCKET_LOCATION=asia
$ SERVICE_ACCOUNT_DEST=/Users/jeonghunbyeon/boscoin/infrastructure/gcp/test2-env/credentials.json

$ hal config storage gcs edit --project $PROJECT \
    --bucket-location $BUCKET_LOCATION \
    --json-path $SERVICE_ACCOUNT_DEST
+ Get current deployment
  Success
+ Get persistent store
  Success
- No changes supplied.

스토리지 소스를 GCS로 지정한다.

$ hal config storage edit --type gcs
+ Get current deployment
  Success
+ Get persistent storage settings
  Success
- No changes supplied.

이제 설정이 끝났으니 정말 Spinnaker를 배포할 차례이다. 다음 명령어로 배포할 Spinnaker 버전을 확인할 수 있다.

$ hal version list
+ Get current deployment
  Success
+ Get Spinnaker version
  Success
+ Get released versions
  Success
+ You are on version "1.8.5", and the following are available:
 - 1.6.2 (GLOW):
   Changelog: https://gist.github.com/spinnaker-release/3fc52e64bae26f8ea1c68bcd8383d4b5
   Published: Fri Jul 27 06:55:31 KST 2018
   (Requires Halyard >= 0.41.0)
 - 1.7.7 (Ozark):
   Changelog: https://gist.github.com/spinnaker-release/8fa68517da00675a028dbd62c72d6748
   Published: Fri Jul 27 06:28:03 KST 2018
   (Requires Halyard >= 1.0.0)
 - 1.8.4 (Dark):
   Changelog: https://gist.github.com/spinnaker-release/ad1c07a861e61c1d4777da7b5c6bda24
   Published: Fri Jul 27 07:04:25 KST 2018
   (Requires Halyard >= 1.0.0)
 - 1.8.5 (Dark):
   Changelog: https://gist.github.com/spinnaker-release/19a850b9081d0fd00a9ac607dfc3d8e0
   Published: Fri Aug 03 05:40:52 KST 2018
   (Requires Halyard >= 1.0.0)

테스트에서 최신 버전을 사용하지 않을 이유가 없으므로 1.8.5를 선택하고 버전을 설정한다.

$ VERSION=1.8.5
$ hal config version edit --version $VERSION
+ Get current deployment
  Success
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.fasterxml.jackson.databind.util.ClassUtil (file:/opt/halyard/lib/jackson-databind-2.8.8.jar) to constructor java.lang.Void()
WARNING: Please consider reporting this to the maintainers of com.fasterxml.jackson.databind.util.ClassUtil
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
+ Edit Spinnaker version
  Success
+ Spinnaker has been configured to update/install version "1.8.5".
  Deploy this version of Spinnaker with `hal deploy apply`.

설정이 끝났으므로 Spinnaker를 배포한다.

$ hal deploy apply
+ Get current deployment
  Success
+ Prep deployment
  Success
Problems in default.security:
- WARNING Your UI or API domain does not have override base URLs
  set even though your Spinnaker deployment is a Distributed deployment on a
  remote cloud provider. As a result, you will need to open SSH tunnels against
  that deployment to access Spinnaker.
? We recommend that you instead configure an authentication
  mechanism (OAuth2, SAML2, or x509) to make it easier to access Spinnaker
  securely, and then register the intended Domain and IP addresses that your
  publicly facing services will be using.

+ Preparation complete... deploying Spinnaker
+ Get current deployment
  Success
+ Apply deployment
  Success
+ Run `hal deploy connect` to connect to Spinnaker.

설치 중에 인증과 관련해서 안내 메시지가 나오지만 여기서는 일단 설치해서 테스트해보는 것이 목적이므로 그냥 넘어간다. 프로덕션에서 실제 배포 도구로 사용하려면 세세한 설정을 손봐야 할 것 같다.

설치가 끝났으므로 설치한 Spinnaker에 접속해 보자. 그냥은 접속되지 않으므로 다음 명령어로 Kubernetes에 설치한 Spinnaker에 접속할 수 있다. 이 명령어가 로컬에서 Kubernetes 클러스터로 터널링을 해주는 거로 보인다.

$ hal deploy connect
+ Get current deployment
  Success
+ Connect to Spinnaker deployment.
  Success
Forwarding from 127.0.0.1:8084 -> 8084
Forwarding from [::1]:8084 -> 8084
Forwarding from 127.0.0.1:9000 -> 9000
Forwarding from [::1]:9000 -> 9000

9000 포트는 Spinnaker의 관리 UI인 Deck이고 8084 포트는 API 게이트웨이인 gate이다.

http://localhost:9000/로 접속하면 다음과 같이 Spinnaker 화면을 볼 수 있다.

Spinnaker UI

글이 길어져서 Spinnaker로 배포 설정하는 부분은 좀 더 공부해보고...

2018/08/16 02:52 2018/08/16 02:52