먼저 velero 를 EKS 내에 설치한다.

 

NAME                        	NAMESPACE  	REVISION	UPDATED                                	STATUS  	CHART                             	APP VERSION
velero                      	velero     	1       	2024-08-19 06:23:06.226760291 +0000 UTC	deployed	velero-7.1.5                      	1.14.0

 

helm chart repository url :

https://vmware-tanzu.github.io/helm-charts/

 

[ velero repo image ]

 

docker.io/velero/velero (for a container):

 

  • Velero의 주 애플리케이션 이미지를 나타냅니다.
  • 백업, 복원, 및 Kubernetes 클러스터의 데이터를 스냅샷하는 작업을 수행하는 Velero의 코어 기능을 제공합니다.

 

 

docker.io/velero/velero-plugin-for-aws (for an init container):

  • AWS용 플러그인 이미지입니다.
  • Velero가 AWS S3 버킷에 데이터를 백업하고, EBS 볼륨 스냅샷을 관리할 수 있도록 AWS에 필요한 통합 기능을 제공합니다.

 

위의 두 이미지를 사용해 velero helm chart 로 벨레로 어플리케이션을 배포한다.

 

그 외 배포시 지정 값:

벨레로 백업 내용 저장을 위한 s3 bucket name, s3 region, 생성할 velero backupstorage location 명, velero service account(eks) with iam role

 

Cross Account A에서 백업한 내용으로 B Account 에서 백업 Restore를 진행하여, velero service account 에 iam role 을 매칭하였다.

# example

Name:                velero-service-account
Namespace:           velero
Labels:              app.kubernetes.io/instance=velero
                     app.kubernetes.io/managed-by=Helm
                     app.kubernetes.io/name=velero
                     helm.sh/chart=velero-7.1.5
Annotations:         eks.amazonaws.com/role-arn: arn:aws:iam::<account id>:role/blahblah-velero-role
                     meta.helm.sh/release-name: velero
                     meta.helm.sh/release-namespace: velero

 

그 다음 velero CLI 를 설치한다.

 

공식 문서: https://velero.io/docs/v1.10/basic-install/#install-the-cli:~:text=a%20Windows%20node.-,Install%20the%20CLI,choco%20install%20velero,-Install%20and%20configure

Install the CLI
Option 1: MacOS - Homebrew
On macOS, you can use Homebrew to install the velero client:
brew install velero

Option 2: GitHub release
Download the latest release’s tarball for your client platform.Extract the tarball:
tar -xvf <RELEASE-TARBALL-NAME>.tar.gz
Move the extracted velero binary to somewhere in your $PATH (/usr/local/bin for most users).

Option 3: Windows - Chocolatey
On Windows, you can use Chocolatey to install the velero client:
choco install velero

 

 

설치 후, velero CLI 를 통해 백업을 생성한다.

 

velero backup create my-eksbackup-2400112233 --storage-location my-backup-location-name --volume-snapshot-locations my-volume-snapshot-location

# you can check the backup status using by below commands.
velero backup describe my-eksbackup-2400112233
velero backup logs my-eksbackup-2400112233

velero backup get
velero backup-location get # or kubectl get backupstoragelocation -n velero

 

 

정상적일 경우, backup-location get 시 PHASE 가 available 이라고 나온다.

 

생성한 백업본을 바탕으로 복구 시 아래 명령어 (restore) 를 사용한다.

velero restore create --from-backup my-eksbackup-2400112233
velero restore logs <restored backup name>
velero restore describe <restored backup name>

 

 

지원되는 명령어 옵션을 미리 확인하여, 사용되지 않는 방식으로 명령어 입력을 하지 않도록 한다.

 

velero backup create [command] 설명(help):



Usage:

  velero backup create NAME [flags]



Examples:

  # Create a backup containing all resources.

  velero backup create backup1



  # Create a backup including only the nginx namespace.

  velero backup create nginx-backup --include-namespaces nginx



  # Create a backup excluding the velero and default namespaces.

  velero backup create backup2 --exclude-namespaces velero,default



  # Create a backup based on a schedule named daily-backup.

  velero backup create --from-schedule daily-backup



  # View the YAML for a backup that doesn't snapshot volumes, without sending it to the server.

  velero backup create backup3 --snapshot-volumes=false -o yaml



  # Wait for a backup to complete before returning from the command.

  velero backup create backup4 --wait



Flags:

      --csi-snapshot-timeout duration                      How long to wait for CSI snapshot creation before timeout.

      --data-mover string                                  Specify the data mover to be used by the backup. If the parameter is not set or set as 'velero', the built-in data mover will be used

      --default-volumes-to-fs-backup optionalBool[=true]   Use pod volume file system backup by default for volumes

      --exclude-cluster-scoped-resources stringArray       Cluster-scoped resources to exclude from the backup, formatted as resource.group, such as storageclasses.storage.k8s.io(use '*' for all resources). Cannot work with include-resources, exclude-resources and include-cluster-resources.

      --exclude-namespace-scoped-resources stringArray     Namespaced resources to exclude from the backup, formatted as resource.group, such as deployments.apps(use '*' for all resources). Cannot work with include-resources, exclude-resources and include-cluster-resources.

      --exclude-namespaces stringArray                     Namespaces to exclude from the backup.

      --exclude-resources stringArray                      Resources to exclude from the backup, formatted as resource.group, such as storageclasses.storage.k8s.io. Cannot work with include-cluster-scoped-resources, exclude-cluster-scoped-resources, include-namespace-scoped-resources and exclude-namespace-scoped-resources.

      --from-schedule string                               Create a backup from the template of an existing schedule. Cannot be used with any other filters. Backup name is optional if used.

  -h, --help                                               help for create

      --include-cluster-resources optionalBool[=true]      Include cluster-scoped resources in the backup. Cannot work with include-cluster-scoped-resources, exclude-cluster-scoped-resources, include-namespace-scoped-resources and exclude-namespace-scoped-resources.

      --include-cluster-scoped-resources stringArray       Cluster-scoped resources to include in the backup, formatted as resource.group, such as storageclasses.storage.k8s.io(use '*' for all resources). Cannot work with include-resources, exclude-resources and include-cluster-resources.

      --include-namespace-scoped-resources stringArray     Namespaced resources to include in the backup, formatted as resource.group, such as deployments.apps(use '*' for all resources). Cannot work with include-resources, exclude-resources and include-cluster-resources.

      --include-namespaces stringArray                     Namespaces to include in the backup (use '*' for all namespaces). (default *)

      --include-resources stringArray                      Resources to include in the backup, formatted as resource.group, such as storageclasses.storage.k8s.io (use '*' for all resources). Cannot work with include-cluster-scoped-resources, exclude-cluster-scoped-resources, include-namespace-scoped-resources and exclude-namespace-scoped-resources.

      --item-operation-timeout duration                    How long to wait for async plugin operations before timeout.

  -L, --label-columns stringArray                          Accepts a comma separated list of labels that are going to be presented as columns. Names are case-sensitive. You can also use multiple flag options like -L label1 -L label2...

      --labels mapStringString                             Labels to apply to the backup.

      --or-selector orLabelSelector                        Backup resources matching at least one of the label selector from the list. Label selectors should be separated by ' or '. For example, foo=bar or app=nginx

      --ordered-resources string                           Mapping Kinds to an ordered list of specific resources of that Kind.  Resource names are separated by commas and their names are in format 'namespace/resourcename'. For cluster scope resource, simply use resource name. Key-value pairs in the mapping are separated by semi-colon.  Example: 'pods=ns1/pod1,ns1/pod2;persistentvolumeclaims=ns1/pvc4,ns1/pvc8'.  Optional.

  -o, --output string                                      Output display format. For create commands, display the object but do not send it to the server. Valid formats are 'table', 'json', and 'yaml'. 'table' is not valid for the install command.

      --parallel-files-upload int                          Number of files uploads simultaneously when running a backup. This is only applicable for the kopia uploader

      --resource-policies-configmap string                 Reference to the resource policies configmap that backup using

  -l, --selector labelSelector                             Only back up resources matching this label selector. (default <none>)

      --show-labels                                        Show labels in the last column

      --snapshot-move-data optionalBool[=true]             Specify whether snapshot data should be moved

      --snapshot-volumes optionalBool[=true]               Take snapshots of PersistentVolumes as part of the backup. If the parameter is not set, it is treated as setting to 'true'.

      --storage-location string                            Location in which to store the backup.

      --ttl duration                                       How long before the backup can be garbage collected.

      --volume-snapshot-locations strings                  List of locations (at most one per provider) where volume snapshots should be stored.

  -w, --wait                                               Wait for the operation to complete.



Global Flags:

      --add_dir_header                   If true, adds the file directory to the header of the log messages

      --alsologtostderr                  log to standard error as well as files (no effect when -logtostderr=true)

      --colorized optionalBool           Show colored output in TTY. Overrides 'colorized' value from $HOME/.config/velero/config.json if present. Enabled by default

      --features stringArray             Comma-separated list of features to enable for this Velero process. Combines with values from $HOME/.config/velero/config.json if present

      --kubeconfig string                Path to the kubeconfig file to use to talk to the Kubernetes apiserver. If unset, try the environment variable KUBECONFIG, as well as in-cluster configuration

      --kubecontext string               The context to use to talk to the Kubernetes apiserver. If unset defaults to whatever your current-context is (kubectl config current-context)

      --log_backtrace_at traceLocation   when logging hits line file:N, emit a stack trace (default :0)

      --log_dir string                   If non-empty, write log files in this directory (no effect when -logtostderr=true)

      --log_file string                  If non-empty, use this log file (no effect when -logtostderr=true)

      --log_file_max_size uint           Defines the maximum size a log file can grow to (no effect when -logtostderr=true). Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800)

      --logtostderr                      log to standard error instead of files (default true)

  -n, --namespace string                 The namespace in which Velero should operate (default "velero")

      --one_output                       If true, only write logs to their native severity level (vs also writing to each lower severity level; no effect when -logtostderr=true)

      --skip_headers                     If true, avoid header prefixes in the log messages

      --skip_log_headers                 If true, avoid headers when opening log files (no effect when -logtostderr=true)

      --stderrthreshold severity         logs at or above this threshold go to stderr when writing to files and stderr (no effect when -logtostderr=true or -alsologtostderr=true) (default 2)

  -v, --v Level                          number for the log level verbosity

      --vmodule moduleSpec               comma-separated list of pattern=N settings for file-filtered logging

 

 

velero backup-location [command] 설명(help):


Usage:

  velero backup-location [command]



Available Commands:

  create      Create a backup storage location

  delete      Delete backup storage locations

  get         Get backup storage locations

  set         Set specific features for a backup storage location



Flags:

  -h, --help   help for backup-location



Global Flags:

      --add_dir_header                   If true, adds the file directory to the header of the log messages

      --alsologtostderr                  log to standard error as well as files (no effect when -logtostderr=true)

      --colorized optionalBool           Show colored output in TTY. Overrides 'colorized' value from $HOME/.config/velero/config.json if present. Enabled by default

      --features stringArray             Comma-separated list of features to enable for this Velero process. Combines with values from $HOME/.config/velero/config.json if present

      --kubeconfig string                Path to the kubeconfig file to use to talk to the Kubernetes apiserver. If unset, try the environment variable KUBECONFIG, as well as in-cluster configuration

      --kubecontext string               The context to use to talk to the Kubernetes apiserver. If unset defaults to whatever your current-context is (kubectl config current-context)

      --log_backtrace_at traceLocation   when logging hits line file:N, emit a stack trace (default :0)

      --log_dir string                   If non-empty, write log files in this directory (no effect when -logtostderr=true)

      --log_file string                  If non-empty, use this log file (no effect when -logtostderr=true)

      --log_file_max_size uint           Defines the maximum size a log file can grow to (no effect when -logtostderr=true). Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800)

      --logtostderr                      log to standard error instead of files (default true)

  -n, --namespace string                 The namespace in which Velero should operate (default "velero")

      --one_output                       If true, only write logs to their native severity level (vs also writing to each lower severity level; no effect when -logtostderr=true)

      --skip_headers                     If true, avoid header prefixes in the log messages

      --skip_log_headers                 If true, avoid headers when opening log files (no effect when -logtostderr=true)

      --stderrthreshold severity         logs at or above this threshold go to stderr when writing to files and stderr (no effect when -logtostderr=true or -alsologtostderr=true) (default 2)

  -v, --v Level                          number for the log level verbosity

      --vmodule moduleSpec               comma-separated list of pattern=N settings for file-filtered logging

코스: 과천향교 - 연주암 - 연주대 - 서울대공대 

거리: 5km 3.5시간

 

  • 구성
    • Cross Account 로 EKS 가 있는 A 계정의 prometheus pod에서 AMP가 있는 B 계정으로 전송
  • 선수 조건
    • external provisioner 이 kube-system 에 설치되어있어야 합니다.
    • prometheus-server Pod (alert manager pod 포함) 가 pvc 를 생성하므로, 결합할 수 있는 unbound pv와 storage class가 존재해야 합니다.

 

 

  • Helm 으로 EKS 클러스터 prometheus 네임스페이스에 프로메테우스 설치
  • 헬름 설치:
curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash

 

  • 리포지토리 추가 :
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts

 

  • 헬름 리포로 설치:
helm install prometheus prometheus-community/prometheus -n prometheus --create-namespace --version 25.21.0

 

  • prometheus-server에 아래와 같은 iam 역할 추가:

 

 

한 계정에 AMP, EKS가 존재할때

    remote_write:
    - queue_config:
        capacity: 2500
        max_samples_per_send: 1000
        max_shards: 200
      sigv4:
        region: <region>
        role_arn: arn:aws:iam::<account id>:role/<AMP iam role>
      url: https://aps-workspaces.<region>.amazonaws.com/workspaces/<workspace id>/api/v1/remote_write
 

 

A 계정에 EKS, B 계정에 AMP 가 존재하는 Cross Account 구성 시

 

server:
  persistentVolume:
    accessModes:
    - ReadWriteOnce // for an example
    enabled: <true or false>
    mountPath: <mount path>
    size: <storage capacity>
    storageClass: <storage class>
  remoteWrite:
  - queue_config:
      capacity: 2500
      max_samples_per_send: 1000
      max_shards: 200
    sigv4:
      region: <B ACCOUNT REGION>
      role_arn: arn:aws:iam::<B ACCOUNT>:role/<B ACCOUNT AMP ROLE NAME>
    url: https://aps-workspaces.<AMP REGION>.amazonaws.com/workspaces/<AMP WORKSPACE ID>/api/v1/remote_write
serviceAccounts:
  server:
    annotations:
      eks.amazonaws.com/role-arn: arn:aws:iam::<A ACCOUNT>:role/<A ACCOUNT EKS IRSA ROLE NAME>
    name: <SERVICE ACCOUNT NAME>

 

 

실제 values.yaml (테스트 환경, A 계정. workspace url은 B계정의 AMP 워크스페이스)

$ cat values.yaml 
serviceAccounts:
    server:
        name: "amp-iamproxy-ingest-service-account"
        annotations:
            eks.amazonaws.com/role-arn: "<A 계정 EKS IRSA용 IAM Role>"
server:
    remote_write:
    - queue_config:
        capacity: 2500
        max_samples_per_send: 1000
        max_shards: 200
      sigv4:
        region: <AMP WORKSPACE REGION>
        role_arn: <B 계정 AMP 용 IAM Role>
      url: https://aps-workspaces.<REGION>.amazonaws.com/workspaces/<AMP WORKSPACE ID>/api/v1/remote_write

 

 

 

해당 value 로 헬름 업그레이드를 하면 기존 prometheus-server 서비스계정이 사라지고 역할 이름으로 서비스 계정이 자동 생성됩니다.

 

프로메테우스 로그:

ts=2024-06-27T08:01:38.254Z caller=kubernetes.go:331 level=info component="discovery manager notify" discovery=kubernetes config=config-0 msg="Using pod service account via in-cluster config"
ts=2024-06-27T08:01:38.254Z caller=main.go:1402 level=info msg="Completed loading of configuration file" filename=/etc/config/prometheus.yml totalDuration=7.206003ms db_storage=1.31µs remote_storage=1.439µs web_handler=710ns query_engine=1.139µs scrape=1.467289ms scrape_sd=1.487768ms notify=85.852µs notify_sd=995.151µs rules=204.247µs tracing=6.131µs

 

A 계정 IAM 권한(A 계정에 EKS, B 계정에 AMP 가 존재하는 Cross Account 구성 시):

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": [
                "arn:aws:iam::<B 계정 ACCOUNT ID>:role/<B 계정 AMP IAM ROLE NAME"
            ]
        }
    ]
}

 

 

 

해당 A계정 역할의 신뢰 정책:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::<A Acccount Id>:oidc-provider/oidc.eks.<region>.amazonaws.com/id/<OIDC Id>"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "oidc.eks.<region>.amazonaws.com/id/<OIDC Id>:aud": "sts.amazonaws.com",
                    "oidc.eks.<region>.amazonaws.com/id/<OIDC Id>:sub": "system:serviceaccount:prometheus:amp-iamproxy-ingest-service-account"
                }
            }
        }
    ]
}

 

service account 다음에는 프로메테우스용 네임스페이스, 서비스 계정 이름입니다.

 

 

 

B 계정 IAM 역할 권한(A 계정에 EKS, B 계정에 AMP 가 존재하는 Cross Account 구성 시):

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "aps:RemoteWrite",
                "aps:QueryMetrics"
            ],
            "Resource": "*"
        }
    ]
}

 

 

B 계정 해당 역할의 신뢰정책:

A 계정의 해당 역할을 허용하는 부분이 존재합니다.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Statement1",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<A Account Id>:role/<Role name>"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

 

 

공식 문서의 설정을 참고하는 것이 좋습니다.

문서: https://aws.amazon.com/ko/blogs/opensource/setting-up-cross-account-ingestion-into-amazon-managed-service-for-prometheus/

 

Setting up cross-account ingestion into Amazon Managed Service for Prometheus | Amazon Web Services

April 21, 2021: This article has been updated to reflect changes introduced by Sigv4 support on Prometheus server. The recently launched Amazon Managed Service for Prometheus (AMP) service provides a highly available and secure environment to ingest, query

aws.amazon.com

 

기타 설정 오류 관련:

 

컨테이너에서 해당 에러 확인시 (컨테이너로 올릴시 uid gid 불일치 문제)

에러 메시지:

panic: Unable to create mmap-ed active query log

goroutine 1 [running]:
github.com/prometheus/prometheus/promql.NewActiveQueryTracker({0x7ffebd0d142b, 0x5}, 0x14, {0x4424b60, 0xc00042e960})
	/app/promql/query_logger.go:146 +0x425

 

ec2 node 에 ssh 하여 아래 명령어 수행시 정상 running

sudo chown -R 65534:65534 /data/prometheus 
sudo chmod -R 775 /data/prometheus

 

'devops > ETC' 카테고리의 다른 글

Hashcorp Vault with a simple demo  (0) 2024.06.23
Pulumi with a simple demo  (0) 2024.06.23
Istio - service mesh  (2) 2024.06.15
Aqua Security / Trivy  (2) 2024.06.15
Cross Plane 이란  (0) 2024.06.15

Vault Overview

HashiCorp Vault는 API 기반의 클라우드에 종속되지 않는 비밀 관리 시스템입니다.

하이브리드 클라우드 환경에서 민감한 데이터를 안전하게 저장하고 관리할 수 있습니다.

또한 Vault를 사용하여 동적 단기 자격 증명 (credentials)을 생성하거나 애플리케이션 데이터를 즉석에서 암호화할 수 있습니다.

Vault는 SaaS (HCP)와 설치 모델 두가지를 제공합니다.



Vault License

Vault 라이센스 종류는 OSS와 Enterprise 로 나누어져 있습니다.

 

엔터프라이즈 라이센스의 주요 기능

엔터프라이즈 라이센스의 주요 기능은 다음과 같습니다.

네임스페이스

  • 하나의 Vault 시스템에 또 다른 Vault 시스템을 구성하여, 서로 격리된 정책, ID&PW, 보안데이터를 관리
  • 보안, 규정 준수를 위한 멀티 테넌트 환경
  • 격리된 Vault 시스템 별 규정 준수 시행
 

MFA

  • Vault는 다양한 인증 유형을 사용하여 MFA를 지원하며, TOTP (Time-based one-time password)를 제공
  • Vault TOTP 암호화 토큰을 조합하여 유사한 TOTP 유틸리티를 활용
  • Okta, Duo, PingID 인증 유형 사용
 

DR

  • 주센터와 DR센터에 Vault 시스템을 구성하여, 통합된 보안데이터를 복제
  • 센터간의 복제는 네트워크로 수행
  • Async 방식으로 복제되며, 주기적으로 데이터 동기화 진행
 

성능 복제 (Performance Replication)

  • Vault는 보안 데이터의 고도화된 이중화 환경을 위해 멀티 데이터 센터 복제 방식을 제공
  • 다중 데이터센터 복제 - 1 : N 제공
  • 복제되는 모든 Vault 시스템은 중앙에서 통합하여 관리
 

복제 필터

  • 서로 다른 클러스터 간 복제 대상과, 복제가 되지 않아야 하는 대상을 설정하여, 복제 성능을 향상
  • 복제 대상을 Path를 등록하여 설정
  • 복제를 하지 않는 대상을 Path로 등록하여 설정
 

리드 리플리카 (Read Replicas)

  • Vault 클러스터의 Active 서버는 Read/Write를 수행하고, 나머지 서버에서 Read 수행
  • Read I/O 분산 처리로 고성능 제공
  • Vault 서버 장애 시에도 남은 서버로 서비스가 되는 무중단 운영 환경
 

Sentinel Integration

  • 비밀 정보는 Path로 구성되며, Path 마다 RBAC를 설정하여, 고도화된 보안 환경 구축
  • 비밀 정보 Path 마다, create, read, write, update, delete중 필요한  정책 적용
  • 세밀한 보안 정책 적용 가능
 

임대 카운트 쿼터 (Lease Count Quotas)

  • 시스템 안정성 및 대규모 스토리지 성능을 보호하기 위해 생성 된 키들의 수를 제한
  • 비밀 정보 Path 마다 생성될 수 있는 키의 수를 제안 (Quota)
  • 필요 이상으로 생성된 불필요한 키 관리
 

Vault 를 사용하면 좋은 점

  • 하드코딩된 자격증명 보안 이슈 및 수동관리의 어려움을 대체할 수 있다.
    • 네트워크 경계 전반에 걸쳐 보안을 확장할 수 있는 ID 기반 규칙출처를 유지하기 위한 개별 계정
    • 쉽게 무효화될 수 있는 자격 증명 (credentials) 및 엔터티(Entities)
    • 자주 교체되는 동적 단기 자격 증명
  • 많은 시스템에 대해 사용자와 응용 프로그램을 인증할 수 있도록 지원한다.

 

 

 


사용법

  • Vault 는 CLI 를 제공하며 보안 읽기, 쓰기 등 수행할 수 있습니다.
  • Vault 서버는 두 가지 모드로 실행할 수 있습니다.
    • "Dev" mode : 개발 목적으로 만 사용
      • 유의할 점: 볼트의 데브 모드는 안전하지 않습니다.Vault는 자동으로 봉인 해제됩니다."Dev" 모드에서 실행되는 서버에 실제 비밀을 저장하지 마십시오.
      • 루트 토큰은 시작하기 전에 지정할 수 있습니다.
      • 메모리에 모든 것을 저장합니다.
    • "Prod" mode : QA와 운영 목적으로 사용
      • "Prod" 모드에서 Vault 서버를 실행하려면 여러 단계를 거쳐야 합니다.
        1. Config file에서 구성을 지정합니다.
        2. 서버를 시작합니다.
        3. Unseal keys와 initial root token을 얻기 위해 서버를 초기화합니다.
        4. Unseal keys로 Vault 서버의 봉인을 해제합니다.
  • Vault 는 Vault UI 가 지원됩니다.
    • UI를 사용하려면 처음에 로그인을 해야합니다.
    • 새 Vault 서버는 처음에 토큰 인증 방법만 활성화됩니다.
    • 토큰 인증 방법을 사용하고 ”root"를 토큰으로 지정하는 방법이 있습니다.
  • Vault 는 Vault API를 제공합니다.
    • JSON 출력 형식을 지정하기 위해 jq가 뒤에 오는 간단한 curl 명령어를 사용하여 Vault의 상태를 확인할 수 있습니다.
    • Command 예: curl http://localhost:8200/v1/sys/health | jq
# Result
{
  "initialized": true,
  "sealed": false,
  "standby": false,
  "performance_standby": false,
  "replication_performance_mode": "disabled",
  "replication_dr_mode": "disabled",
  "server_time_utc": 1655600004,
  "version": "1.10.4+ent",
  "cluster_name": "vault-cluster-92ffexxx",
  "cluster_id": "3522f7f4-a977-9547-2cf2-xxxxxxxxxx",
  "last_wal": 61334,
  "license": {
    "state": "autoloaded",
    "expiry_time": "2023-06-10T23:59:59Z",
    "terminated": false
  }
}

 

 

Vault API 인증은 X-Vault-Token 헤더와 함께 Vault 토큰으로 수행됩니다.

 

 

  • 볼트 컨피그를 구성하고 프로덕션 서버 시작하기
    • "Prod" 모드에서 Vault 서버를 실행하려면 여러 단계를 거쳐야 합니다.
      • Vault configuration files 은 HCL 또는 JSON으로 지정할 수 있습니다.
      • listener
      • seal
      • uicluster_addr
      • api_addr
      • log_level
      • storage
    •  일반적인 구성 설정은 다음과 같습니다.
      • 서버를 시작합니다.
      • Unseal keys와 initial root token을 얻기 위해 서버를 초기화합니다.
      • Unseal keys로 Vault 서버의 봉인을 해제합니다.
      • -dev 옵션 없이 vault server 명령어로 Production 서버를 시작합니다.
    • Config file에서 구성을 지정합니다.
  • 볼트 클러스터 초기화하기
    • Vault 클러스터는 여러 Vault 서버를 실행하여 구성합니다.이는 Vault의 vault operator init 으로 수행됩니다.이 명령은 클러스터에 대한 unseal keys와 initial root token을 반환합니다.
    • 키 공유 수와 키 임계값은 –key-shares 및 key-threshold 옵션을 사용하여 지정할 수 있습니다.
    • 각 Vault 클러스터는 한 번 초기화해야 합니다.
    • 각 Vault 서버는 시작할 때마다 봉인(Seal)을 해제해야 합니다.이는 클러스터를 초기화할 때 반환된 unseal keys를 사용하여
      vault operator unseal 명령어로 수행됩니다.
    • 봉인을 해제할 때까지 서버를 사용할 수 없습니다.
    • vault status 명령어로 상태 확인 가능하며 봉인 되었는지 아닌지 확인 가능합니다.
$ vault status
WARNING! VAULT_ADDR and -address unset. Defaulting to https://127.0.0.1:8200.
Error checking seal status: Get "https://127.0.0.1:8200/v1/sys/seal-status": http: server gave HTTP response to HTTPS client
$ export VAULT_ADDR='http://127.0.0.1:8200' # no tls for this test demo
$ vault status
Key             Value
---             -----
Seal Type       shamir
Initialized     true
Sealed          false
Total Shares    1
Threshold       1
Version         1.17.0
Build Date      2024-06-10T10:11:34Z
Storage Type    inmem
Cluster Name    vault-cluster-445bxxxx
Cluster ID      6748b197-b91c-89a2-36f3-a78cxxxxxxxx
HA Enabled      false

 

 

  • 볼트 시크릿 엔진
    • 대부분의 Vault 비밀 엔진은 명시적으로 활성화해야 합니다.각 비밀 엔진에는 기본 경로가 있습니다.그러면 CLI 명령 및 API 호출에서 사용자 지정 경로를 지정해야 합니다.
      vault write aws/config/root  대신 vault write aws-east/config/root
    • 여러 인스턴스를 활성화하기 위해 대체 경로(path)를 지정할 수 있습니다.
      vault secrets enable -path=aws-east aws
    • vault secrets enable 명령어로 수행됩니다.
    • 볼트 엔진 버전은 현재 두가지가 있습니다.
      • KV v1(버전 관리 없음)
      • KV v2(버전 관리 포함)
      • Dev mode는 Vault 서버에 대해 KV v2 엔진의 인스턴스가 자동으로 활성화됩니다.
      • Vault는 "Prod" mode 서버에서 KV 시크릿 엔진의 인스턴스를 자동으로 활성화하지 않습니다. 따라서 직접 활성화해야 합니다.
      • 기본 경로 kv에 KV v2 secrets 엔진의 인스턴스를 마운트하는 방법
        vault secrets enable -version=2 kv
        • vault kv list는 지정된 경로에 있는 보안 비밀을 나열합니다.vault kv get은 지정된 경로에서 보안 비밀을 읽습니다.
        • vault kv delete는 지정된 경로에서 보안 비밀을 삭제합니다.
        • vault kv put은 지정된 경로에 보안 비밀을 작성합니다.
 

볼트 인증

  • 볼트 인증 방법은 유저, 어플리케이션 대상 두가지로 나눠져 있습니다.
    • Methods for UsersGitHubJWT/OIDC
    • Okta
    • LDAP
    • Userpass
    • Methods for ApplicationsAWSGoogle Cloud
    • Kubernetes
    • Azure
    • AppRole
  • 대부분의 Vault 인증 방법은 명시적으로 활성화해야 합니다.각 인증 방법에는 기본 경로가 있습니다.CLI 명령 및 API 호출에서 사용자 지정 경로를 지정해야 합니다.
    vault write aws/config/root 대신 vault write aws-east/config/root
  • 여러 인스턴스를 활성화하기 위해 대체 경로를 지정할 수 있습니다.
    vault auth enable -path=aws-east aws
  • 이는 vault auth enable 명령어로 수행됩니다.

볼트 정책(Policy)

  • Vault Policies는 사용자와 애플리케이션이 액세스할 수 있는 secrets (비밀) 을 제한합니다.
  • Vault는 기본적으로 액세스를 거부하는 최소 권한 관행을 따릅니다.
  • Vault 관리자는 정책 설명을 사용하여 특정 경로에 대한 사용자 및 애플리케이션 액세스 권한을 명시적으로 부여해야 합니다.
  • 경로를 지정하는 것 외에도 정책은 해당 경로에 대한 기능 집합도 지정합니다.
  • Policies 는 HashiCorpConfiguration Language (HCL)로 작성됩니다.
    • 예시:
# Allow tokens to look up their own properties
path "auth/token/lookup-self" {
capabilities = ["read"]
}

 

정책 경로는 Vault API 경로에 매핑됩니다.

Vault의 CLI, UI 또는 API를 사용하여 Vault 서버에 Vault 정책을 추가할 수 있습니다.

CLI로 정책을 추가하는 명령어는 vault policy write 입니다

정책을 생성하고 사용자와 연결하는 예시:

 

vault policy write lob-A-dept-1 lob-A- dept-1-policy.hcl
vault write auth/userpass/users/joe/policies Policies=lob-A-dept-1

사용법

먼저 볼트를 ec2 linux 에 설치해 봅니다.

sudo yum install -y yum-utils
# Add repo
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo
# Install Vault
sudo yum -y install vault
Installed:
  vault-1.17.0-1.aarch64                                                                                                                             

Complete!
$ vault version
Vault v1.17.0 (72850df1bc10581b74ba5f0f7b373xxxxxxx), built 2024-06-10T10:11:34Z

간단한 테스트를 위해, dev mode를 활성화하여 볼트를 시작합니다.

$ vault server -dev
==> Vault server configuration:

Administrative Namespace: 
             Api Address: http://127.0.0.1:8200
                     Cgo: disabled
         Cluster Address: https://127.0.0.1:8201
   Environment Variables: BASH_FUNC_which%%, DBUS_SESSION_BUS_ADDRESS, GOTRACEBACK, HISTCONTROL, HISTSIZE, HOME, HOSTNAME, LANG, LESSOPEN, LOGNAME, LS_COLORS, MAIL, MOTD_SHOWN, NVM_BIN, NVM_CD_FLAGS, NVM_DIR, NVM_INC, NVM_RC_VERSION, OLDPWD, PATH, PWD, SELINUX_LEVEL_REQUESTED, SELINUX_ROLE_REQUESTED, SELINUX_USE_CURRENT_RANGE, SHELL, SHLVL, SSH_CLIENT, SSH_CONNECTION, SSH_TTY, SYSTEMD_COLORS, S_COLORS, TERM, USER, XDG_RUNTIME_DIR, XDG_SESSION_CLASS, XDG_SESSION_ID, XDG_SESSION_TYPE, _, which_declare
              Go Version: go1.22.4
              Listener 1: tcp (addr: "127.0.0.1:8200", cluster address: "127.0.0.1:8201", disable_request_limiter: "false", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled")
               Log Level: 
                   Mlock: supported: true, enabled: false
           Recovery Mode: false
                 Storage: inmem
                 Version: Vault v1.17.0, built 2024-06-10T10:11:34Z
             Version Sha: 72850df1bc10581b74ba5f0f7b3xxxxxxxx

==> Vault server started! Log data will stream in below:
...
WARNING! dev mode is enabled! In this mode, Vault runs entirely in-memory
and starts unsealed with a single unseal key. The root token is already
authenticated to the CLI, so you can immediately begin using Vault.

You may need to set the following environment variables:

    $ export VAULT_ADDR='http://127.0.0.1:8200'

The unseal key and root token are displayed below in case you want to
seal/unseal the Vault or re-authenticate.

Unseal Key: lS0Xa99RlRkP/g2reElBKYhnJggXcOtxxxxxxxxx
Root Token: hvs.EI1TksGnXihdxxxxxxxx

Development mode should NOT be used in production installations!

 

 

볼트 서버 상태를 확인합니다.

$ export VAULT_ADDR='http://127.0.0.1:8200'
$ vault status
Key             Value
---             -----
Seal Type       shamir
Initialized     true
Sealed          false
Total Shares    1
Threshold       1
Version         1.17.0
Build Date      2024-06-10T10:11:34Z
Storage Type    inmem
Cluster Name    vault-cluster-44xxxxx
Cluster ID      6748b197-b91c-89a2-36f3-axxxxxxxx
HA Enabled      false

 

 

key value 로 시크릿을 생성하기 위해 kv 명령어를 실행합니다.

$ vault kv put -mount=secret hello team=banana
== Secret Path ==
secret/data/hello

======= Metadata =======
Key                Value
---                -----
created_time       2024-06-23T06:53:49.203123729Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1

 

 

dev 모드로 볼트 서버를 시작한 경우, 기본 Mount path은 자동으로 생성됩니다.

data hello가 secret/data/hello 로 key value 로 마운트 되었습니다.

kv put으로 여러 key value를 입력할 수 있습니다.

$ vault kv put -mount=secret hello team=banana homework=yes
== Secret Path ==
secret/data/hello

======= Metadata =======
Key                Value
---                -----
created_time       2024-06-23T06:57:10.424550787Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            2

이제 시크릿을 get 으로 읽어봅니다.

$ vault kv get -mount=secret hello
== Secret Path ==
secret/data/hello

======= Metadata =======
Key                Value
---                -----
created_time       2024-06-23T06:57:10.424550787Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            2

====== Data ======
Key         Value
---         -----
homework    yes
team        banana

특정 키의 value 값만 읽습니다. 옵션과 명령어 넣을때 순서를 인식합니다.

$ vault kv get -mount=secret hello -field=homework
Command flags must be provided before positional arguments. The following arguments will not be parsed as flags: [-field=homework]
Too many arguments (expected 1, got 2)
$ vault kv get -mount=secret -field=homework hello
yes

 

 

이제 AWS 엔진을 활성화 하고 동적 AWS 시크릿을 생성해 봅니다.

동적 비밀은 액세스할 때 생성됩니다. 동적 시크릿은 읽을 때까지 존재하지 않으므로 누군가가 이를 훔치거나 동일한 비밀을 사용하는 다른 클라이언트가 발생할 위험이 없습니다.

Vault에는 취소 메커니즘이 내장되어 있으므로 동적 시크릿은 사용 후 즉시 취소되어 비밀이 존재하는 시간을 최소화할 수 있습니다.

일단 aws 엔진을 다음 명령어로 활성화합니다.

$ vault secrets enable -path=aws aws
Success! Enabled the aws secrets engine at: aws/

 

 

이제 AWS 시크릿 엔진을 구성해봅니다.

참고로 STS 페더레이션 토큰을 사용하려는 경우 IAM 역할 자격 증명으로 볼트를 인증할 수 없습니다.

역할과 연결된 임시 보안 자격 증명에는 GetFederationToken을 사용할 권한이 없기 때문입니다.

대안으로 identity token audience 를 사용하는 방법이 있는데 무료 커뮤니티 버전은 지원이 안됩니다.

$ vault write aws/config/root \
    identity_token_audience="http://127.0.0.1:8200" \
    role_arn="arn:aws:iam::539666729110:role/gepp-demo01-ssm-assume-ec2-role"
Error writing data to aws/config/root: Error making API request.

URL: PUT http://127.0.0.1:8200/v1/aws/config/root
Code: 400. Errors:

* failed to generate plugin identity token: plugin workload identity not supported in Vault community edition

 

 

export 한 access key value를 써서 구성해봅니다.

$ vault write aws/config/root \
    access_key=$AWS_ACCESS_KEY_ID \
    secret_key=$AWS_SECRET_ACCESS_KEY \
    region=ap-southeast-1
Success! Data written to: aws/config/root

이제 IAM Role을 생성해봅니다. 크레덴셜이 가리키는 유저가 수행할 역할이며 ec2 에 대한 권한을 주었습니다.

$ vault write aws/roles/gepp-vault-demo-test-role \
        credential_type=iam_user \
        policy_document=-<<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1426528957000",
      "Effect": "Allow",
      "Action": [
        "ec2:*"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}
EOF
Success! Data written to: aws/roles/gepp-vault-demo-test-role

 

확인해 봅니다.

 

 

암호화된 access_key, secret_key 정보가 확인됩니다. (실제값과 다른 암호화된 값, 아래는 추가 보안을 위해 임의 스트링 집어넣음)

$ vault read aws/creds/gepp-vault-demo-test-role
Key                Value
---                -----
lease_id           aws/creds/gepp-vault-demo-test-role/mOw57QlxKdPeZvZAdlxxxxx
lease_duration     768h
lease_renewable    true
access_key         AKIXABCDABxxxxxxx
secret_key         ARABCDABCDABCDABxxxxxxxxx
session_token      <nil>

이제 액세스 및 비밀 키를 사용하여 AWS 내에서 EC2 작업을 수행할 수 있습니다.

이 키는 위에서 말했듯이 새로운 값이며 이전에 입력한 키가 아닙니다.

명령을 두 번째로 실행하면 또 달라진 새 액세스 키 쌍을 얻게 됩니다.

aws/creds/:name에서 읽을 때마다 Vault는 AWS에 연결하고 새로운 IAM 사용자 및 키 쌍을 생성합니다.

해당 access key로 다시 aws credential 을 export 하고 aws cli를 날리면 자원이 생성됩니다.

즉 실제 값이 아닌 시크릿 값으로 사용할 수 있습니다.

실제로 볼트 시크릿 값으로 명령을 실행해 봅니다.

$ vault read aws/creds/gepp-vault-demo-test-role
Key                Value
---                -----
lease_id           aws/creds/gepp-vault-demo-test-role/HqC1JKt1F48xvzMrAxxxxxx
lease_duration     768h
lease_renewable    true
access_key         AKIAX3JVEZCXXXXXXX // <- 임의로 X 로 가림
secret_key         oBQHHrE+wfTd6LTQa+80UV7LiHHpdXXXXXXXXXX 
session_token      <nil>
$ export AWS_ACCESS_KEY_ID=AKIAX3JVEZCLXXXXXXX
$ export AWS_SECRET_ACCESS_KEY=oBQHHrE+wfTd6LTQa+80UV7LiHHpd7gXXXXXXXX
$ aws ec2 run-instances \
> --image-id ami-001f48902dxxxxx \
> --count 1 \
> --key-name gepp-demo01-key \
> --subnet-id subnet-0aedd5xxxxxxx \
> --security-group-ids sg-024ebxxxxxxxx \
> --instance-type t4g.nano
{
    "Groups": [],
    "Instances": [
        {
            "AmiLaunchIndex": 0,
            "ImageId": "ami-001f489xxxxxxxxx",
            "InstanceId": "i-0b00d5xxxxxxxxx",
            "InstanceType": "t4g.nano",
            "KeyName": "gepp-demo01-key",
            "LaunchTime": "2024-06-23T07:45:52+00:00",
            "Monitoring": {
                "State": "disabled"
            },
            "Placement": {
                "AvailabilityZone": "ap-southeast-1a",
                "GroupName": "",
                "Tenancy": "default"
            },
            "PrivateDnsName": "ip-192-168-0-xx.ap-southeast-1.compute.internal",
            "PrivateIpAddress": "192.168.0.xx",
            "ProductCodes": [],
            "PublicDnsName": "",
            "State": {
                "Code": 0,
                "Name": "pending"
            },
 

출력에 있는 이 Lease_id 값의 전체 경로를 복사해서 갱신, 해지 및 검사에 사용할 수 있습니다.

시크릿 철회(Revoke)하기

Vault는 768시간 후에 이 사용자 인증 정보를 자동으로 취소하지만(출력의 lease_duration 참조)

조기에 취소하고 싶은 경우,

시크릿을 취소하려면 실행 시 볼트 읽기에서 출력된 임대 ID와 함께 볼트 임대 취소를 수행하면 됩니다.

비밀이 취소되면 해당 시크릿의 액세스 키는 더 이상 유효하지 않습니다.

$ vault lease revoke aws/creds/gepp-vault-demo-test-role/mOw57QlxKdPeZvZAdlxxxxxx
All revocation operations queued successfully!

# 서버 로그
2024-06-23T16:33:59.115+0900 [INFO]  expiration: revoked lease: lease_id=aws/creds/gepp-vault-demo-test-role/mOw57QlxKdPeZvZAdlxxxxx

위의 취소했던 시크릿의 액세스키 값으로 export 하고 ec2를 다시 생성해봅니다.

임대 취소된 값:

Key                Value

---                -----

lease_id           aws/creds/cnp-soyip-vault-demo-test-role/mOw57QlxKdPeZvZxxxxx
lease_duration     768h
lease_renewable    true
access_key         AKIAX3JVEZCLNXXXX. // ← export
secret_key         ARVWzrUjYCIcnF/WZFnRAiWrOML+mh6vPXXXXXX
session_token      <nil>

$ export AWS_ACCESS_KEY_ID=AKIAX3JVEZCLNPU6XXXX
$ export AWS_SECRET_ACCESS_KEY=ARVWzrUjYCIcnF/WZFnRAiWrOML+mh6vPH7XXXXX
$ aws ec2 run-instances --image-id ami-001f48902dca0ecb9 --count 1 --key-name cnp-soyip-bastion01-key --subnet-id subnet-0aedd591757a7ea1f --security-group-ids sg-024eb29d41a2d037e --instance-type t4g.nano

An error occurred (AuthFailure) when calling the RunInstances operation: AWS was not able to validate the provided access credentials

// 임대 취소되어 해당값으로 생성 불가

이외 참고 문서

Vault pricing: https://www.hashicorp.com/products/vault/pricing

Vault Tutorial: https://developer.hashicorp.com/vault/tutorials/getting-started/getting-started-intro

Vault AWS cred: https://developer.hashicorp.com/vault/docs/secrets/aws#assumed_role

Overview

Pulumi 는 클라우드 인프라를 생성, 배포, 관리할 수 있는 IaC 오픈소스 툴이며, Pulumi Cloud 와 결합하여 사용할 수 있습니다.

TypeScript, JavaScript, Python, Go, .NET, Java 및 YAML과 같은 마크업 언어 등 기존 프로그래밍 언어와 해당 기본 에코시스템을 활용하여 클라우드 리소스와 상호 작용합니다.

CLI , SDK, 런타임, 라이브러리 및 호스팅 서비스가 함께 작동하여 클라우드 인프라 프로비저닝, 업데이트 및 관리를 위한 강력한 플랫폼을 제공합니다.

그리고 여러 클라우드를 지원하고 있습니다.

 

Pulumi 구조

 

보다시피 스택 구조로 되어있으며, 새 인프라를 선언하려면

해당 속성이 원하는 인프라 상태에 해당하는 리소스 개체를 할당합니다.

이러한 속성은 필요한 종속성을 처리하기 위해 리소스 간에도 사용되며 필요한 경우 스택 외부로 내보낼 수 있습니다.

플루미 프로그램은 소스코드와 메타데이터가 있는 project 폴더에 있고 pulumi up 명령어를 하게 되면

스택이 생성됩니다.

Pulumi 설치

Linux OS

$ curl -fsSL https://get.pulumi.com | sh
$ pulumi version
v3.121.0

typescript 를 이용해 S3 버킷을 생성하기 위하여 먼저 nodejs를 설치해봅니다.

$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
$ nvm install 20
Now using node v20.15.0 (npm v10.7.0)
Creating default alias: default -> 20 (-> v20.15.0)
$ node -v
v20.15.0
$ npm -v
10.7.0

AWS credential 을 확인해 봅니다. ec2 iam role로 사용하며, 해당 역할은 생성할 S3에 대한 권한과 sts 권한을 갖고 있어야 합니다.

$ aws sts get-caller-identity
{
    "UserId": "AROAX3JVEZxxxxxxxx:i-0ae8021f62xxxxxx",
    "Account": "53966xxxxxxx",
    "Arn": "arn:aws:sts::539xxxxxxxx:assumed-role/gepp-demo01-ssm-assume-ec2-role/i-0ae8021fxxxxxxx"
}

Pulumi 사용

이제 명령어 pulumi new aws-typscript 를 사용하여 새 프로젝트를 생성합니다.

$ pulumi new aws-typescript
Manage your Pulumi stacks by logging in.
Run `pulumi login --help` for alternative login options.
Enter your access token from https://app.pulumi.com/account/tokens
    or hit  to log in using your browser                   :  


  Welcome to Pulumi!

  Pulumi helps you create, deploy, and manage infrastructure on any cloud using
  your favorite language. You can get started today with Pulumi at:

      https://www.pulumi.com/docs/get-started/

  Tip: Resources you create with Pulumi are given unique names (a randomly
  generated suffix) by default. To learn more about auto-naming or customizing resource
  names see https://www.pulumi.com/docs/intro/concepts/resources/#autonaming.


This command will walk you through creating a new Pulumi project.

Enter a value or leave blank to accept the (default), and press .
Press ^C at any time to quit.

project name (project): aws-create-s3-with-ts 
project description (A minimal AWS TypeScript Pulumi program): cnp demo for pulumi 
Created project 'aws-create-s3-with-ts'

Please enter your desired stack name.
To create a stack in an organization, use the format / (e.g. `acmecorp/dev`).
stack name (dev): dev 
Created stack 'dev'

The packagemangager to use for installing dependencies npm
aws:region: The AWS region to deploy into (us-east-1): ap-southeast-1 
Saved config

Installing dependencies...
added 422 packages, and audited 423 packages in 4m

60 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
Finished installing dependencies

Your new project is ready to go! 

To perform an initial deployment, run `pulumi up`

$ ls
Pulumi.dev.yaml  Pulumi.yaml  index.ts  node_modules  package-lock.json  package.json  tsconfig.json

Pulumi yaml 은 지정했던 값이 들어가 있습니다.

$ cat Pulumi.yaml 
name: aws-create-s3-with-ts
runtime:
  name: nodejs
  options:
    packagemanager: npm
description: cnp demo for pulumi
config:
  pulumi:tags:
    value:
      pulumi:template: aws-typescript
$ cat Pulumi.dev.yaml
config:
  aws:region: ap-southeast-1

이제 index.ts 를 수정하여 버킷 이름을 지정합니다.

$ cat index.ts 
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";

// Create an AWS resource (S3 Bucket)
const bucket = new aws.s3.Bucket("gepp-demo01-pulumi-test-bucket01");

// Export the name of the bucket
export const bucketName = bucket.id;

aws 에러를 피하기 위해 pulumi up을 하기전에 먼저 크레덴셜이 정상적으로 s3 리소스로 접근 가능한지 테스트 해봅니다.

aws s3 ls

이제 스택 배포 및 버킷 생성을 하기 위해 pulumi up 명령어를 실행합니다.

$ pulumi up
Previewing update (dev)

View in Browser (Ctrl+O): https://app.pulumi.com/INSANECRAB/aws-create-s3-with-ts/dev/previews/b929de47-a0e9-4f72-88c4-7ddexxxxxxx

     Type                 Name                            Plan       
 +   pulumi:pulumi:Stack  aws-create-s3-with-ts-dev       create     
 +   └─ aws:s3:Bucket     gepp-demo01-pulumi-test-bucket01  create     

Outputs:
    bucketName: output

Resources:
    + 2 to create

Do you want to perform this update? yes
Updating (dev)

View in Browser (Ctrl+O): https://app.pulumi.com/INSANECRAB/aws-create-s3-with-ts/dev/updates/1

     Type                 Name                            Status           
 +   pulumi:pulumi:Stack  aws-create-s3-with-ts-dev       created (7s)     
 +   └─ aws:s3:Bucket     gepp-demo01-pulumi-test-bucket01  created (1s)     

Outputs:
    bucketName: "gepp-demo01-pulumi-test-bucket01-ffa34xx"

Resources:
    + 2 created

Duration: 9s

$ aws s3 ls | grep gepp-demo
2024-06-23 15:36:30 gepp-demo01-pulumi-test-bucket01-ffa34xx

 

 

Pulumi Console 에서 방금 배포한 내용이 확인됩니다.

 
 
 

참고 문서

dynamic credentials with AWS OIDC 를 위해 pulumi yaml 에 아래와 같은 설정을 추가할 수도 있습니다.

https://www.pulumi.com/registry/packages/aws/installation-configuration/#dynamically-generate-credentials-via-pulumi-esc

 

기본 샘플이라 생각하고 여기서 더 효율적으로 수정 반영이 가능합니다.

 

  • 구성
    • helm chart fluent-bit -> AWS Opensearch 전송
      • Opensearch user, password 대신 IAM 권한으로 오픈서치에 연결
# fluent-bit configmap

apiVersion: v1
data:
  custom_parsers.conf: |
    [PARSER]
        Name    custom-tag
        Format  regex
        Regex   ^(?<namespace_name>[^_]+)\.(?<pod_name>[a-z0-9](?:[-a-z0-9]*[a-z0-9])?(?:\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)\.(?<container_name>.+)\.(?<container_id>[a-z0-9]{64})

    [MULTILINE_PARSER]
        Name multiline_regex
        Type regex
        Flush_Timeout 1000
        Rule "start_state" "/^(\d+\-\d+\-\d+) (.*)/" "cont"
        Rule "cont" "/^(?!\d+\-\d+\-\d+).*/" "cont"
  fluent-bit.conf: |
    [SERVICE]
        Daemon Off
        Flush 1
        Log_Level info
        Parsers_File custom_parsers.conf
        HTTP_Server On
        HTTP_Listen 0.0.0.0
        HTTP_Port 2020
        Health_Check On

    [INPUT]
        Name tail
        Path /var/log/containers/*my-service*.log
        Exclude_Path /var/log/containers/kube-*.log,/var/log/containers/eks-*.log,/var/log/containers/*-csi-*.log,/var/log/containers/aws-*.log,/var/log/containers/argocd-*.log,/var/log/containers/metrics-*.log,/var/log/containers/fluent-*.log
        multiline.parser docker, cri
        Tag               my-service.<namespace_name>.<pod_name>.<container_name>.<container_id>

        Tag_Regex (?<pod_name>[a-z0-9](?:[-a-z0-9]*[a-z0-9])?(?:\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)_(?<namespace_name>[^_]+)_(?<container_name>.+)-(?<container_id>[a-z0-9]{64})\.log$
        Mem_Buf_Limit 64MB
        Skip_Long_Lines On
        Skip_Empty_Lines On
        Buffer_Chunk_Size 64KB
        Buffer_Max_Size 256KB

    [FILTER]
        Name kubernetes
        Match my-service.*
        Kube_Tag_Prefix my-service.
        Regex_Parser custom-tag
        Kube_URL https://kubernetes.default.svc:443
        Kube_CA_File /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
        Kube_Token_File /var/run/secrets/kubernetes.io/serviceaccount/token
        Keep_Log Off
        Merge_Log On
        Merge_Log_Key log
        K8S-Logging.Parser On
        K8S-Logging.Exclude On

    [FILTER]
        Name multiline
        Match my-service.*
        Multiline.Parser multiline_regex
        Multiline.key_content log
        Buffer off

    [OUTPUT]
        Name opensearch
        Match my-service.*
        Host ${OPENSEARCH_ENDPOINT}
        Port 443
        #HTTP_User ${OPENSEARCH_USER}
        #HTTP_Passwd ${OPENSEARCH_PASSWORD}
        TLS On
        AWS_Auth On
        AWS_Region ${AWS_REGION}
        Index ${INDEX_NAME}-%Y%m%d
        Type _doc
        Replace_Dots On
        Suppress_Type_Name On
kind: ConfigMap
metadata:
  annotations:
    meta.helm.sh/release-name: fluent-bit
    meta.helm.sh/release-namespace: logging
  labels:
    app.kubernetes.io/instance: fluent-bit
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: fluent-bit
    app.kubernetes.io/version: 3.0.4
    helm.sh/chart: fluent-bit-0.46.7
  name: fluent-bit
  namespace: logging

 

 

${} 로 감싸진 부분은 daemonset env 에서 넘겨줘야 합니다.

my-service 부분은 서비스 이름에 맞게 커스터마이징 할 수 있습니다.

 

        env:
        - name: TZ
          value: Asia/Seoul
        - name: OPENSEARCH_ENDPOINT
          value: yourdomain.com
        - name: AWS_REGION
          value: ap-northeast-2
        - name: INDEX_NAME
          value: my-service-logs

 

 

 

오픈 서치 (OpenSearch) 에서 확인되는 모습

 

 

  • 환경
    • Mac with Public Secured Wifi -> Public EC2 -> Private Load Balancers and Private EC2 Proxy -> docker on Private EC2

 

# Modify /private/etc/hosts file

127.0.0.1 <Target Domain>

 

 

# Modify .zshrc file

alias <alias name>='ssh -i <your key file name>.pem <username>@<public EC2 IP> -p <public EC2 port> \
	-g -L <local port which is not in use>:<target domain name>:<target port> \
    -g -L <local port which is not in use>:<target domain name>:<target port>'

 

source .zshrc
<type alias name>

 

터미널에서 Public EC2 에 들어가지면 브라우저에서 <접속할 타겟 도메인>:<지정한 로컬포트> 로 입력합니다.

Public EC2 를 거쳐 내부 Private 도메인에 접속이 됩니다.

이때 접속할 소스가 Public EC2 보안그룹에 허용되어 있어야 합니다.

 

Service Mesh


 

Service Mesh는 마이크로서비스 아키텍처에서 서비스 간의 통신을 관리하는 인프라 계층입니다.

즉 서비스 간의 상호작용을 더욱 효율적이고 안전하게 만들기 위해 다양한 기능을 제공합니다.

Service Mesh는 주로 다음과 같은 기능을 포함합니다:

트래픽 관리: 서비스 간의 트래픽을 제어하고 라우팅합니다. 이를 통해 A/B 테스트, 카나리아 배포, 트래픽 분할 등을 쉽게 구현할 수 있습니다.
서비스 디스커버리: 서비스 인스턴스가 동적으로 변경될 때 이를 자동으로 감지하고 업데이트합니다.
로드 밸런싱: 서비스 요청을 여러 인스턴스에 고르게 분산시켜 시스템의 부담을 줄입니다.
보안: 서비스 간 통신을 암호화하고 인증을 관리하여 보안성을 높입니다.
모니터링 및 로깅: 서비스 간의 통신 데이터를 수집하고 분석하여 성능 문제를 파악하고 문제를 해결하는 데 도움을 줍니다.
정책 관리: 서비스 간의 통신 규칙을 설정하고 적용합니다.
ETC: 또한 서비스 메시는 A/B 테스트, 카나리아 배포, 속도 제한, 액세스 제어, 암호화, 엔드투엔드 인증과 같은 보다 복잡한 운영 요구 사항을 해결하는 경우도 있습니다.
Service Mesh는 일반적으로 사이드카 패턴을 사용하여 구현됩니다. 각 서비스 인스턴스 옆에 프록시(사이드카 프록시)를 배치하고, 이 프록시가 서비스 간의 모든 트래픽을 처리합니다.

이를 통해서 애플리케이션 코드의 변경 없이 통신 기능을 추가할 수 있습니다.

대표적인 Service Mesh 솔루션으로는 Istio, Linkerd, Consul 등이 있습니다.

해당 도구로 마이크로서비스 환경에서의 복잡성을 줄이고,

개발자와 운영자가 더 쉽게 서비스 간의 통신을 관리할 수 있게됩니다.

 

 

 

How to use Istio Service Mesh in Kubernetes

 


 

 

Helm 으로 설치하기

kubectl create namespace istio-system

helm repo add istio https://istio-release.storage.googleapis.com/charts
helm repo update
helm install <release> <chart> --namespace <namespace> --create-namespace [--set <other_parameters>]
helm install istio-base istio/base -n istio-system --set defaultRevision=default

 

 

설치되면 다음과 같이 DEPLOYED 로 확인됩니다.

$ helm status istiod -n istio-system
NAME: istiod
LAST DEPLOYED: Fri Jan 20 22:00:44 2023
NAMESPACE: istio-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
"istiod" successfully installed!

 

또한 Istio 는 istioctl 명령어를 제공하여, 해당 명령어로 설치할 수도 있습니다.

설치하고 나중에 어플리케이션 배포하면 Istio가 Envoy sidecar 프록시를 주입시키도록 라벨을 정할 수 있습니다.

 

$ curl -L https://istio.io/downloadIstio | sh -
$ cd istio-<version>
$ export PATH=$PWD/bin:$PATH

$ istioctl install --set profile=demo -y

# Add a namespace label to instruct Istio to automatically inject Envoy sidecar proxies
$ kubectl label namespace default istio-injection=enabled

 

애플리케이션 배포 후, 바깥쪽에서 접근 가능하게 하여 서비스 메쉬 엣지로 라우팅할 수 있도록 path를 맵핑하는 

Istio Ingress Gateway를 설정합니다.

 

kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
gateway.networking.istio.io/bookinfo-gateway created
virtualservice.networking.istio.io/bookinfo created

# check the config
$ istioctl analyze
✔ No validation issues found when analyzing namespace: default.

# check if there's external load balancer to support
kubectl get svc istio-ingressgateway -n istio-system
NAME                   TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)                                      AGE
istio-ingressgateway   LoadBalancer   172.21.109.129   130.211.10.121  80:31380/TCP,443:31390/TCP,31400:31400/TCP   17h

 

 

bookinfo-gateway.yaml

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: bookinfo-gateway
spec:
  # The selector matches the ingress gateway pod labels.
  # If you installed Istio using Helm following the standard documentation, this would be "istio=ingress"
  selector:
    istio: ingressgateway # use istio default controller
  servers:
  - port:
      number: 8080
      name: http
      protocol: HTTP
    hosts:
    - "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bookinfo
spec:
  hosts:
  - "*"
  gateways:
  - bookinfo-gateway
  http:
  - match:
    - uri:
        exact: /productpage
    - uri:
        prefix: /static
    - uri:
        exact: /login
    - uri:
        exact: /logout
    - uri:
        prefix: /api/v1/products
    route:
    - destination:
        host: productpage
        port:
          number: 9080

 

 

Official document to install Istio: https://istio.io/latest/docs/setup/install/

 

Installation Guides

Choose the guide that best suits your needs and platform.

istio.io

 

Getting started: https://istio.io/latest/docs/setup/getting-started/#download

'devops > ETC' 카테고리의 다른 글

Hashcorp Vault with a simple demo  (0) 2024.06.23
Pulumi with a simple demo  (0) 2024.06.23
Aqua Security / Trivy  (2) 2024.06.15
Cross Plane 이란  (0) 2024.06.15
Automation technologies including tech companies  (0) 2023.08.04

+ Recent posts