Tetragon은 eBPF(extended Berkeley Packet Filter)를 기반으로 하는 강력한 보안 및 모니터링 도구이다. eBPF는 커널 레벨에서 실행되는 프로그램으로, 시스템 성능에 최소한의 영향을 주면서 실시간으로 데이터를 수집하고 처리할 수 있다. Tetragon은 이를 활용하여 Kubernetes 환경에서 네트워크 트래픽, 시스템 호출, 컨테이너 활동 등을 모니터링하고 분석할 수 있다.
컨테이너 내부에서 실행 중인 애플리케이션이나 프로세스는 시스템 호출(system call)을 수행할 수 있다. 대표적인 예로 HTTP 요청을 수행하는 curl 명령을 들 수 있다. 시스템 호출은 커널에 서비스를 요청하기 위해 사용자 공간에서 실행되는 추상화된 프로그래밍인데, 커널 강화 도구를 사용하여 허용되는 시스템 호출을 제한할 수 있으며, CKS 시험에서는 AppArmor와 seccomp라는 두 가지 도구를 명시적으로 언급하고 있다. 이 두 도구는 컨테이너화된 환경에서 보안을 강화하는 데 중요한 역할을 하며, Kubernetes와의 통합을 통해 보다 안전한 클러스터 운영을 지원한다. 이 두 도구와 쿠버네티스와 통합하는 메커니즘에 대해 설명한다.
AppArmor는 Linux 시스템에서 실행되는 프로그램에 대한 액세스 제어 기능을 제공한다. AppArmor는 경로 기반으로 작동하며, 프로필을 통해 특정 프로그램이나 컨테이너가 필요한 접근만 허용하도록 설정할 수 있다. Kubernetes에서는 AppArmor 프로필을 Pod 또는 컨테이너 수준에서 지정할 수 있으며, securityContext를 통해 적용한다. 이 도구는 user space에서 호출되는 애플리케이션과 기본 시스템 기능 사이에 추가적인 보안 계층을 구현한다. 네트워크 호출 또는 파일 시스템 상호 작용을 제한할 수 있다. 많은 Linux 배포판(예: Debian, Ubuntu, openSUSE)이 AppArmor를 기본으로 제공한다. AppArmor를 지원하지 않는 Amazon Linux와 같은 배포판은 AppArmor와 유사한 접근 방식을 취하는 SELinux를 대신 사용할 수 있다.
Kyverno는 그리스어로 "지배하다, 다스리다"의 뜻으로 쿠버네티스 네이티브로 설계된 정책 엔진(policy engine)이다. Kyverno 정책을 활용하여 쿠버네티스 리소스가 정책에 부합하는지 검사하고, 필요하면 리소스를 변경하거나 생성할 수 있다. Kyverno 구조 및 동작 방식을 간단히 정리한다.
OPA Gatekeeper는 독자적인 policy 언어인 Rego를 사용하여 policy를 정의하만
kyverno는 쿠버네티스 리소스로 관리되며 정책을 작성하는 데 새로운 언어가 필요하지 않다. OPA Gatekeeper와 유사하게 pre-defined policy library 를 제공한다.
제한된 예산과 시간, 인력으로 서비스를 만들다 보니 어려운 점들이 참 많다. 특히나 TLS 인증서 같은 경우 관리하는것이 은근히 귀찮다. 인증서 만료일 관리하는것 부터 어느 페이지까지를 평문으로만 두어야 하는지도... 그런데 바보같은 이슈를 저지르고 말았다. 도메인을 신청하고 fanout, Name based virtual hosting 방식중에 고민하다가 설계를 virtual host로 하였다.
그런데 문제는 어이없는곳에서 나왔다. *.xxxxx.io 라고 wildcard SSL 인증서를 신청하였는데 virtual host방식으로 2차 subdomin (예, api.stg.xxxxx.io)으로 ingress를 마구잡이로 생성하고 인증서를 적용을 했다. 하지만 인증서 오류 ㅋㅋ
인터넷 비지니스를 거의 해보지 않아서 인지, 이런 기본적인 내용도 간과하고 서비스를 구상한 내가 모든걸 책임져야하는 상황이 와버렸다.
설계를 이상하게 해서 wildcard 도메인을 몇십개를 신규로 계약해야하는 쓸데없는 비용을 들어야하는 처지가 되었다. 하지만 그냥 죽으란 법은 없는게 사람사는 세상이고 이런 고민들을 분명 다른사람들도 했을거야라고 생각하면서 떠오른게 let's encrypt 였고 찾아보니 이걸 또 kubernetes에서 발급부터 갱신까지 해주는 오픈소스를 찾아 적용까지 하고 이렇게 포스팅을 한다.
인증서 없이 구성할수도 있지만 기본적으로 kubernetes 는 secret과 ingress의 간단한 설정만으로 TLS를 구성할 수 있다.
Cert-manager : K8s 클러스터내에서 TLS인증서를 자동으로 프로비저닝 및 관리하는 오픈소스
Let’s Encrypt : 자율적으로 작동하는 개방된 CA(Certificate authority-인증기관)으로 공공성(공공의 이익)을 위해서 운영되는 오픈소스
Cert-manager는 AWS의 Certificate Manager와 유사하게 인증서를 발급하고 설정할수 있다. 3개월 유효기간을 가지는 let's encrypt를 사용하기에 인증서 만료시 문제가 될거라 생각했지만 이것도 자동으로 갱신을 해주는 관리 app.을 같이 배포하기 때문에 인증서 관리에 대한 부담을 덜수 있다.
기본적으로 Cert-manager는 let's encrypt, Vault 같은 것을들 사용하여 인증서 발급을 할 수 있다. 인증서 발급후에도 만료가 되기 전에 바로 갱신을 자동으로 한다.
$ helm install --name cert-manager --version v0.3.1 \ --namespace kube-system stable/cert-manager $ helm status cert-manager LAST DEPLOYED: Fri Jun 15 10:02:45 2018 NAMESPACE: kube-system STATUS: DEPLOYED RESOURCES: ==> v1/Pod(related) NAME READY STATUS RESTARTS AGE cert-manager-cert-manager-5f76b676b4-5tdh8 1/1 Running 0 2d ==> v1/ServiceAccount NAME SECRETS AGE cert-manager-cert-manager 1 28d ==> v1beta1/CustomResourceDefinition NAME AGE certificates.certmanager.k8s.io 28d clusterissuers.certmanager.k8s.io 28d issuers.certmanager.k8s.io 28d ==> v1beta1/ClusterRole cert-manager-cert-manager 28d ==> v1beta1/ClusterRoleBinding NAME AGE cert-manager-cert-manager 28d ==> v1beta1/Deployment NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE cert-manager-cert-manager 1 1 1 1 28d NOTES: cert-manager has been deployed successfully! In order to begin issuing certificates, you will need to set up a ClusterIssuer or Issuer resource (for example, by creating a 'letsencrypt-staging' issuer). More information on the different types of issuers and how to configure them can be found in our documentation: https://cert-manager.readthedocs.io/en/latest/reference/issuers.html For information on how to configure cert-manager to automatically provision Certificates for Ingress resources, take a look at the `ingress-shim` documentation: https://cert-manager.readthedocs.io/en/latest/reference/ingress-shim.html
그리고 issuer manifest를 배포한다.
(letsencrypt-issuer.yaml)
# Copyright 2018 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. apiVersion: certmanager.k8s.io/v1alpha1 kind: ClusterIssuer metadata: name: letsencrypt-staging spec: acme: server: https://acme-staging-v02.api.letsencrypt.org/directory email: '' privateKeySecretRef: name: letsencrypt-staging http01: {} --- apiVersion: certmanager.k8s.io/v1alpha1 kind: ClusterIssuer metadata: name: letsencrypt-prod spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: '' privateKeySecretRef: name: letsencrypt-prod http01: {}
두개의 endpoint를 생성한다. (Staging, Prod)
$ sed -e "s/email: ''/email: $EMAIL/g" letsencrypt-issuer.yaml | \ kubectl apply -f- clusterissuer "letsencrypt-staging" created clusterissuer "letsencrypt-prod" created
Web App을 HTTP Ingress 형태로 배포한다. TLS발급전에 미리 HTTP(80) Ingress를 배포해야 한다. 이후 Let's encrypt TLS배포 후 TLS spec을 추가하고 재배포를 해야한다.
인증서를 발급할때는 위에서 만든 Ingress로 생성하고namespace별 생성이 필요하다.
apiVersion: certmanager.k8s.io/v1alpha1 kind: Certificate metadata: name: auth-dev-tls namespace: auth #### namespace별 생성 spec: secretName: auth-dev-tls issuerRef: name: letsencrypt-prod kind: ClusterIssuer commonName: auth.dev.action.cloudz.co.kr dnsNames: - auth.dev.action.cloudz.co.kr acme: config: - http01: ingress: auth-ingress ### 기존에 만든 HTTP ingress 명 domains: - auth.dev.action.cloudz.co.kr
$ kubectl apply -f auth-dev-tls.yaml certificate "auth-dev-tls" created
이후 TLS 생성 상태를 확인한다. 이때 Message에서 Normal CeritifcateIssued Certificated issued successfully 문구가 확인되면 인증서 발급이 정상적으로 되었다고 볼 수 있다.
이때 발급되는 시간이 네트워크 환경에 따라 1~5분정도 소요될때로 있는것으로 보인다.
$ kubectl describe -f auth-dev-tls.yaml ... Type Reason Message ---- ------ ------- Warning ErrorCheckCertificate Error checking existing TLS certificate: secret "auth-dev-tls" not found Normal PrepareCertificate Preparing certificate with issuer Normal PresentChallenge Presenting http-01 challenge for domain foo.kubernetes.tips Normal SelfCheck Performing self-check for domain auth.dev.action.cloudz.co.kr Normal ObtainAuthorization Obtained authorization for domain auth.dev.action.cloudz.co.kr Normal IssueCertificate Issuing certificate... Normal CeritifcateIssued Certificated issued successfully
$ kubectl apply -f auth-tls-ingress.yaml $ kubectl get ing NAME HOSTS ADDRESS PORTS AGE auth-ingress auth.dev.action.cloudz.co.kr 10.1.1.182 80, 443 14h
설계의 실수로 시작되었지만 정리하다보니 인증서 갱신이 자동을 된다는 점과 또한 Kubernetes환경에서 TLS관리가 간편하다는것을 알게 되었다. 인증서 비용을 아낀것도 하나의 성과이기도 하다. 인증서는 써야하겠고 정말 많은 애플리케이션들을 생성/삭제를 상시 해야하는 환경이라면 한번 적용해볼만한 가치가 있는것 같다.