• 패킷과 밀접한 관련이 있는 것이 네트워크 이더넷 카드
  • 네트워크 디바이스 드라이버와 하드웨어 셋팅을 보거나 설정할 수 있는 ethtool 명령어를 잘 알아야함
  • 이더넷 정보를 확인할 때 대표적인 도구가 ifconfig 명령어 → ifconfig 명령어를 통해 링크상태, IP 주소, 맥 주소, 통신 상태 현황 등을 확인 가능
  • ethtool 명령어는 ifconfig 명령어 보다 더 자세하고 섬세하게 이더넷을 설정하고 확인 가능

1. ethtool 명령어 기본 사용 방법

ethtool [옵션] [ethX] [파라미터]



2. ethtool 명령어 기본 정보 → 링크 모드와 속도, Duplex 상태 출력

  • 일목요연하게 이더넷 인터페이스에 대한 정보 확인 가능
    $ ethtool eth0
    Settings for eth0:
    Supported ports: [ TP ]
    Supported link modes:   10baseT/Half 10baseT/Full
                           100baseT/Half 100baseT/Full
                           1000baseT/Full
    Supports auto-negotiation: Yes
    Advertised link modes:  10baseT/Half 10baseT/Full
                           100baseT/Half 100baseT/Full
                           1000baseT/Full
    Advertised pause frame use: No
    Advertised auto-negotiation: Yes
    Speed: 1000Mb/s
    Duplex: Full
    Port: Twisted Pair
    PHYAD: 0
    Transceiver: internal
    Auto-negotiation: on
    MDI-X: Unknown
    Supports Wake-on: umbg
    Wake-on: d
    Current message level: 0x00000007 (7)
            drv probe link
    Link detected: yes


3. ethtool 명령어에 -s 옵션 사용 → -s 옵션은 속도, Duplex 등의 값을 변경 가능

  • ethtool 명령어에 -s 옵션 사용할 때 설정 참고 자료
    ethtool -s ethX speed N [duplex half|full] [port tp|aui|bnc|mii]
                [autoneg on|off] [advertise N] [phyad N] [xcvr internal|external]
                [wol p|u|m|b|a|g|s|d...]  [sopass xx:yy:zz:aa:bb:cc] [msglvl N |
                msglvl type on|off ...]

  • Auto-negotiation, Speed 및 Duplex를 조정하기 위해서 Auto-negotiation 기능을 Off하고 Speed를 100, Duplex를 half로 설정

    $ ethtool -s eth0 autoneg off speed 100 duplex half
    
    # 설정 변경 반영 확인
    $ ethtool eth0
    Settings for eth0:
    Supported ports: [ TP MII ]
    Supported link modes:   10baseT/Half 10baseT/Full
                           100baseT/Half 100baseT/Full
                           1000baseT/Half 1000baseT/Full
    Supports auto-negotiation: Yes
    Advertised link modes:  Not reported
    Advertised pause frame use: No
    Advertised auto-negotiation: No
    Speed: 100Mb/s
    Duplex: Half
    Port: MII
    PHYAD: 0
    Transceiver: internal
    Auto-negotiation: off
    Supports Wake-on: pumbg
    Wake-on: g
    Current message level: 0x00000033 (51)
            drv probe ifdown ifup
    Link detected: yes

  • ※ 참고
    • 참고로 e1000 드라이버를 사용하고 있는데, 설정이 제대로 반영되지 않는 문제 발생 → NIC 드라이버의 특성 (드라이버의 패치가 필요)
    • 다른 컴퓨터에서 사용하고 있는 r8169 드라이버에서는 변경이 잘 이줘짐
    • ethtool 명령어가 안되면 아래의 modprobe 명령어 사용
    • 사용하는 네트워크 인터페이스에 따라 차이가 있을 수 있다는 점을 참고 필요



4. ethtool 명령어 X, modprobe 명령어로 e1000 드라이버 옵션을 설정 가능 → ethtool 명령어 적용 X

  • modprobe 명령어로 e1000 드라이버에 대한 옵션을 아래와 같은 형태로 설정
    modprobe e1000 [<option>=<VAL1>,<VAL2>,...]

  • Duplex 를 0 으로 설정한 예
    $ modprobe e1000 Duplex=0  (0=auto-negotiate, 1=half, 2=full)


5. ethtool 명령어에 -i 옵션 사용 → 드라이버에 대한 정보 확인

  • e1000 드라이버를 사용하고 있고, eeprom 접근이 가능한지 여부 확인
    $ ethtool -i eth0
    driver: e1000
    version: 7.3.21-k8-NAPI
    firmware-version: N/A
    bus-info: 0000:00:03.0
    supports-statistics: yes
    supports-test: yes
    supports-eeprom-access: yes
    supports-register-dump: yes


6. ethtool 명령어에 -S 옵션 사용 → 인터페이스 통계 정보 확인

  • rx,tx 의 패킷 전송 개수, 바이트 정보, 브로드캐스팅 정보들 확인 가능
  • 대문자 S 를 사용했다는 점을 주의 필요
  • 소문자 s 는 설정 할때 사용
    $ ethtool -S eth0
    NIC statistics:
       rx_packets: 10
       tx_packets: 29
       rx_bytes: 2145
       tx_bytes: 4100
       rx_broadcast: 0
       tx_broadcast: 3
       rx_multicast: 0
       tx_multicast: 18
       rx_errors: 0
       tx_errors: 0
       tx_dropped: 0


7. ethtool 명령어에 -a 옵션 사용 → Pause 파라미터에 대한 정보를 출력

  • Auto Negotiation 정보를 좀 더 상세히 출력
    $ ethtool -a eth0
    Pause parameters for eth0:
    Autonegotiate: on
    RX:  on
    TX:  off


8. ethtool 명령어에 -p 옵션 사용 → 특정 포트에 LED를 깜빡

  • 어뎁터가 4개의 포트를 가지고 있다고 가정하고, eth3번이 어떤 포트인지 알고 싶을때 LED 를 깜빡 거리게 하여 알려줌
    $ ethtool -p eth3


9. ethtool 명령어에 -k 옵션 사용 → 디바이스의 Offload 정보 출력

  • Offload는 이더넷 카드에서 TOE 기능을 지원하게 되면 사용할 수 있는 기능
  • TOE
    • NIC(Network Interface Cards)에서 사용되는 기술
    • 보통 운영체제 상에서 처리되는 TCP/IP 스택을 네트워크 컨트롤러로 내려서 처리
    • 네트워크 처리가 크게 필요한 기가비트나 10G 기가비트같은 고속네트워크에서 유용하게 사용
      $ ethtool -k eth0
      Offload parameters for eth0:
      rx-checksumming: on
      tx-checksumming: on
      scatter-gather: on
      tcp-segmentation-offload: on
      udp-fragmentation-offload: off
      generic-segmentation-offload: on
      generic-receive-offload: on
      large-receive-offload: off
      rx-vlan-offload: on
      tx-vlan-offload: on
      ntuple-filters: off
      receive-hashing: off


10. ethtool 명령어 이외에 lshw명려어를 이용해 network 관련한 정보를 확인 가능

  • lshw(Hardware Lister)는 메모리, 펌웨어 버전, 메인보드, CPU, 네트워크, 디스크 등의 정보를 알려주는 명령어
  • -C 옵션은 lshw에서 제공하는 하드웨어 정보 중 원하는 것만 출력
    $ lshw -C network
    *-network              
         description: Ethernet interface
         product: 82540EM Gigabit Ethernet Controller
         vendor: Intel Corporation
         physical id: 3
         bus info: pci@0000:00:03.0
         logical name: eth0
         version: 02
         serial: 08:00[deleted]:d0
         size: 1Gbit/s
         capacity: 1Gbit/s
         width: 32 bits
         clock: 66MHz
         capabilities: pm pcix bus_master cap_list ethernet physical tp 10bt 10bt-fd 100bt 100bt-fd 1000bt-fd autonegotiation
         configuration: autonegotiation=on broadcast=yes driver=e1000 driverversion=7.3.21-k8-NAPI duplex=full firmware=N/A ip=10.0.2.15 latency=64 link=yes mingnt=255 multicast=yes port=twisted pair speed=1Gbit/s
         resources: irq:10 memory:f0000000-f001ffff ioport:d010(size=8)

  • vegeta 부하테스트의 github 경로 : https://github.com/tsenart/vegeta
  • vegeta는 일정한 요청 속도로 HTTP 서비스를 요청해야 하는 필요성을 기반으로 구축된 다용도 HTTP 부하 테스트
  • 부하 테스트를 사용하면 동시 사용자 요청을 시뮬레이션하여 실제 조건에서 애플리케이션의 동작을 테스트 가능
  • 여러 사용자가 동시에 액세스할 때 응용 프로그램의 동작을 결정하는 데 도움이 될 수 있음
  • vegeta는 Go 프로그래밍 언어로 작성된 오픈 소스 애플리케이션
  • vegeta는 명령줄 유틸리티와 라이브러리로 모두 사용할 가능
  • vageta 오픈 소스는 이름이 멋진 부하 테스트

vegeta 부하테스트의 장점과 단점

vegeta 부하테스트 장점

  • 명령형 cli와 go util 둘 다 지원
  • 초당 보낼 요청 개수를 정할 수 있음
  • 리포트와 그래프를 뽑아 볼 수 있음

vegeta 부하테스트 단점

  • 검색시 드래곤볼의 베지터가 나와서 검색이 불편함
  • 어떤 파라미터가 있는지 확인이 불편함 (Readme 문서만 있음)


vegeta 다운로드 및 설치

1. Linux 시스템에 Vegata를 설치하려면 최신 바이너리 버전을 다운로드

  • github에서 vegeta 오픈소스 다운

    $ wget https://github.com/tsenart/vegeta/releases/download/v12.8.4/vegeta_12.8.4_linux_amd64.tar.gz

2. 바이너리 파일의 압축 해제

  • github에서 다운 받은 vegeta 오픈소스 코드 압축 해제

    $ tar xvfz vegeta_12.8.4_linux_amd64.tar.gz

3. /usr/bin/ 디렉토리에 vegata 애플리케이션을 설치

  • 시스템 전체에서 사용할 수 있도록 바이너리 파일을 /usr/bin/ 디렉토리에 이동

    $ mv vegeta /usr/bin/vegeta

사용가능한 커맨드

  • vegeta 부하테스트는 엄청나게 많은 키워드를 가짐

  • vegeta 부하테스트에서 사용하는 옵션에 대해 간단한 설명

    Usage: vegeta [global flags] <command> [command flags]
    
    global flags:
    -cpus int
          Number of CPUs to use (defaults to the number of CPUs you have)
    -profile string
          Enable profiling of [cpu, heap]
    -version
          Print version and exit
    
    attack command:
    -body string
          Requests body file
    -cert string
          TLS client PEM encoded certificate file
    -chunked
          Send body with chunked transfer encoding
    -connections int
          Max open idle connections per target host (default 10000)
    -duration duration
          Duration of the test [0 = forever]
    -format string
          Targets format [http, json] (default "http")
    -h2c
          Send HTTP/2 requests without TLS encryption
    -header value
          Request header
    -http2
          Send HTTP/2 requests when supported by the server (default true)
    -insecure
          Ignore invalid server TLS certificates
    -keepalive
          Use persistent connections (default true)
    -key string
          TLS client PEM encoded private key file
    -laddr value
          Local IP address (default 0.0.0.0)
    -lazy
          Read targets lazily
    -max-body value
          Maximum number of bytes to capture from response bodies. [-1 = no limit] (default -1)
    -max-workers uint
          Maximum number of workers (default 18446744073709551615)
    -name string
          Attack name
    -output string
          Output file (default "stdout")
    -proxy-header value
          Proxy CONNECT header
    -rate value
          Number of requests per time unit [0 = infinity] (default 50/1s)
    -redirects int
          Number of redirects to follow. -1 will not follow but marks as success (default 10)
    -resolvers value
          List of addresses (ip:port) to use for DNS resolution. Disables use of local system DNS. (comma separated list)
    -root-certs value
          TLS root certificate files (comma separated list)
    -targets string
          Targets file (default "stdin")
    -timeout duration
          Requests timeout (default 30s)
    -unix-socket string
          Connect over a unix socket. This overrides the host address in target URLs
    -workers uint
          Initial number of workers (default 10)
    
    encode command:
    -output string
          Output file (default "stdout")
    -to string
          Output encoding [csv, gob, json] (default "json")
    
    plot command:
    -output string
          Output file (default "stdout")
    -threshold int
          Threshold of data points above which series are downsampled. (default 4000)
    -title string
          Title and header of the resulting HTML page (default "Vegeta Plot")
    
    report command:
    -buckets string
          Histogram buckets, e.g.: "[0,1ms,10ms]"
    -every duration
          Report interval
    -output string
          Output file (default "stdout")
    -type string
          Report type to generate [text, json, hist[buckets], hdrplot] (default "text")
    
    examples:
    echo "GET http://localhost/" | vegeta attack -duration=5s | tee results.bin | vegeta report
    vegeta report -type=json results.bin > metrics.json
    cat results.bin | vegeta plot > plot.html
    cat results.bin | vegeta report -type="hist[0,100ms,200ms,300ms]"



vegeta 부하테스트의 기본 컨맨드 설명

1. attack

  • 공격을 어떻게 할 것인지에 대한 명령
  • -duration 옵션
    • 대상에 요청을 발행하는 시간을 지정 → 얼마동안 공격을 할 것인가 대한 값
    • 내부 동시성 구조의 설정은 -duration 값을 변수로 가지고 있음
    • 테스트의 실제 실행 시간은 응답 지연으로 인해 지정된 것보다 더 길 수 있음
    • 무한 공격에 0 사용
    • 5초 동안 공격 예시
      -duration=5s

  • -rate 옵션

    • 대상에 대해 발행할 시간 단위당 요청 비율을 지정

    • 실제 요청 비율은 가비지 수집 등으로 인해 약간 다를 수 있지만 전반적으로 지정된 값에 매우 가깝게 유지됨

    • 기본적으로 1초에 몇개를 보낼 것인지 결정 → 설정하지 않은 경우 50/1s

    • 만약 0으로 하게 되면 무한으로 요청보내게 되는데 그럴 경우에는 추가적으로 max-workers의 수를 지정 필요

    • host 당 1초에 10번 요청

      -rate=10

  • -max-workers 옵션

    • max-workers는 vegeta를 실행할 때 같이 설정할 수 있는 옵션

    • worker는 만들어져서 공격을 하게 되는데 최대 몇개의 worker을 사용할 것인가에 해당하는 값을 지정

    • -max-workers는 공격에 사용되는 최대 작업자 수 지정

    • 공격에서 사용하는 동시성 수준을 제어하는 데 사용 가능

      -max-workers=10



2. report

  • 결과값에 대해서 어떤 형식으로 볼 것인지에 대해서 설정하는 command
  • 기본 설정인 text 출력 (-type=text)

    1. Requests → 테스트 중에 전송된 총 요청 수와 요청 비율을 출력

    2. Duration → 테스트의 총 기간, 애플리케이션에 대한 부하를 시뮬레이션하는 공격 기간 및 대기 시간을 출력

    3. Latencies → 공격에 포함된 모든 요청의 지연 시간과 인식된 최대 지연 시간의 평균 지연 시간(각각 50번째, 95번째, 99번째 백분위수)을 출력

    4. Bytes In → 요청 본문과 함께 전송 또는 수신된 바이트 수

    5. Bytes Out → 응답 본문과 함께 출력 또는 송신된 바이트 수

    6. Success → 애플리케이션으로 전송된 성공적인 요청의 백분위수를 출력

    7. Status Codes → 수신된 HTTP 응답 코드 및 해당 발생에 대한 카운터를 제공 (0 상태 코드는 요청 전송에 실패를 의미)

      $ echo "GET http://127.0.0.1:9997/" | vegeta attack -duration=5s | vegeta report
      Requests          [total, rate, throughput]                    250, 50.20, 50.20
      Duration           [total, attack, wait]                          4.98s, 4.98s, 369.149µs
      Latencies          [min, mean, 50, 90, 95, 99, max]     256.785µs, 468.522µs, 471.66µs, 537.929µs, 575.639µs, 942.898µs, 3.66ms
      Bytes In           [total, mean]                                   1000, 4.00
      Bytes Out         [total, mean]                                   0, 0.00
      Success            [ratio]                                             100.00%
      Status Codes    [code:count]                                    200:250

  • json 출력 (-type=json)
    $ echo "GET http://127.0.0.1:9997/" | vegeta attack -duration=5s | vegeta report -type=json > result.json
    $ cat result.json
    {
    "latencies": {
      "total": 121239389,
      "mean": 484957,
      "50th": 477588,
      "90th": 524619,
      "95th": 583750,
      "99th": 814515,
      "max": 6793623,
      "min": 262009
    },
    "bytes_in": {
      "total": 1000,
      "mean": 4
    },
    "bytes_out": {
      "total": 0,
      "mean": 0
    },
    "earliest": "2020-12-21T00:59:10.755216634+09:00",
    "latest": "2020-12-21T00:59:15.731910157+09:00",
    "end": "2020-12-21T00:59:15.732195838+09:00",
    "duration": 4976693523,
    "wait": 285681,
    "requests": 250,
    "rate": 50.23415624141097,
    "throughput": 50.231272776682474,
    "success": 1,
    "status_codes": {
      "200": 250
    },
    "errors": []
    }

  • histogram 출력 (-type=hist)

    $ echo "GET http://127.0.0.1:9997/" | vegeta attack -duration=5s | vegeta report -type='hist[0, 2ms, 4ms, 6ms, 8ms, 10ms]'
    Bucket            #       %          Histogram
    [0s,    2ms]    250  100.00%  ##################################################################
    [2ms,   4ms]    0    0.00%   
    [4ms,   6ms]    0    0.00%   
    [6ms,   8ms]    0    0.00%   
    [8ms,   10ms]  0    0.00%   
    [10ms,  +Inf]   0    0.00%

  • plot 이용한 시각화

    • 해당 데이터를 시각화하는 데이터로 만들어줌

    • 기본적으로 html 파일로 만들어주면 거기서 여러 데이터를 동시에 비교하면서 볼 수 있음

      $ vegeta attack -name=50qps -rate=50 -duration=5s -targets=targets.txt > results.50qps.bin
      $ cat results.50qps.bin | vegeta plot > plot.50qps.html



Vegeta로 부하 테스트 실행 → 테스트 진행하면서 정리 예정

1. 30초간 1000회의 요청을 10개의 worker가 실행하여 text 리포터로 출력

  • -rate=1000 → 시간 단위당 요청 비율을 지정(초당 요청 수 결정)

  • -duration=30s → 요청을 발행하는 시간 지정

  • -max-workers=10 → 공격에 사용되는 최대 작업자 수 지정

  • vegeta report → 기본 설정인 text 출력 (-type=text 생략)

    $ echo "GET http://www.hippo.shop/download/spring_music.mp4" | vegeta attack -rate=100 -duration=30s -max-workers=10 | vegeta report
    Requests        [total, rate, throughput]                   109, 3.63, 3.56
    Duration         [total, attack, wait]                          30.58s, 30.046s, 534.21ms
    Latencies        [min, mean, 50, 90, 95, 99, max]     514.095ms, 750.656ms, 666.337ms, 957.774ms, 1.503s, 1.883s, 1.948s
    Bytes In         [total, mean]                                   30293636430, 277923270.00
    Bytes Out       [total, mean]                                   0, 0.00
    Success          [ratio]                                            100.00%
    Status Codes  [code:count]                                   200:109
    Error Set:

2. 1초간 223개의 worker가 무한 요청하여 text 리포터로 출력 (100% 응답할 MAX)

  • -rate=0 → 무한으로 요청보내게 되는데 그럴 경우에는 추가적으로 max-workers의 수를 지정 필요

  • -duration=1s → 요청을 발행하는 시간 지정

  • -max-workers=223 → 공격에 사용되는 최대 작업자 수 지정(-rate=0일 때 필수)

  • vegeta report → 기본 설정인 text 출력 (-type=text 생략)

    $ echo "GET http://www.hippo.shop/download/spring_music.mp4" | vegeta attack -rate=0 -duration=1s -max-workers=223 | vegeta report
    Requests       [total, rate, throughput]                    224, 11.03, 7.62
    Duration        [total, attack, wait]                           29.389s, 20.314s, 9.075s
    Latencies       [min, mean, 50, 90, 95, 99, max]      6.297s, 26.281s, 26.555s, 29.03s, 29.326s, 29.379s, 29.383s
    Bytes In        [total, mean]                                    62254812480, 277923270.00
    Bytes Out      [total, mean]                                    0, 0.00
    Success         [ratio]                                             100.00%
    Status Codes [code:count]                                    200:224
    Error Set:

3. 1초간 224개의 worker가 무한 요청하여 text 리포터로 출력 (응답에 실패가 발생)

  • -rate=0 → 무한으로 요청보내게 되는데 그럴 경우에는 추가적으로 max-workers의 수를 지정 필요

  • -duration=1s → 요청을 발행하는 시간 지정

  • -max-workers=224 → 공격에 사용되는 최대 작업자 수 지정(-rate=0일 때 필수)

  • vegeta report → 기본 설정인 text 출력 (-type=text 생략)

    $ echo "GET http://www.hippo.shop/download/spring_music.mp4" | vegeta attack -rate=0 -duration=1s -max-workers=224 | vegeta report
    Requests        [total, rate, throughput]                  225, 12.44, 7.11
    Duration         [total, attack, wait]                        30.115s, 18.088s, 12.027s
    Latencies        [min, mean, 50, 90, 95, 99, max]   8.999s, 26.799s, 26.853s, 29.753s, 30.001s, 30.07s, 30.11s
    Bytes In         [total, mean]                                 59475579780, 264335910.13
    Bytes Out       [total, mean]                                 0, 0.00
    Success          [ratio]                                           95.11%
    Status Codes  [code:count]                                  0:11  200:214
    Error Set:


Vault로 유효 기간이 존재하는 인증서 관리

  • 인증서를 직접 발급 수행하는 것은 매우 번거러운일
  • Vault를 사용하면 SSH 인증서를 매우 쉽게 관리하고 발급 가능

Vault를 사용하기 위해서는 모든 클라이언트 Server에 Vault가 설치 필요

1. hashicorp_vault 설치

$ yum install -y yum-utils
$ yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
$ yum -y install vault

2. hashicorp_vault 설치 확인

$ vault -v



Vault 서버 기본 설정

1. Vault SSH secret engine 활성화

$ vault secrets enable -path=ssh-client-signer ssh
Success! Enabled the ssh secrets engine at: ssh-client-signer/

# SSH secret enbine 생성 확인
$ vault secrets list
Path                       Type         Accessor              Description
----                        ----          --------                 -----------
ssh-client-signer/     ssh          ssh_241cbffa         n/a

2. SSH CA 생성

$ vault write ssh-client-signer/config/ca generate_signing_key=true
Key              Value
---                -----
public_key    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDALoH6ItfBjGnqNJAwFa1xUzOJ38WVosCNZQ3o2BlFJxhXvejU1CalDQDCZXEK8SIxeOqKC3mu/nIGMLYR5lwWRgl5r3janyLw8174MSM1wgSy9ZcURZrivicafKrH2WQAXJ6TKsrlhR5GODwxRCciD02l8LgbvaBs8pt1SRmvCc17xBAMuwu/A0pBU+tHotfiBqeLlQThi2mhpRSZ9u2cIt4neP/g+1/hMDxjlhmge7ehQBNYyWc2n8HDubCYT+z2GANk8vk6DhXs5iaLozM1lALXQZlbK3MpIVh1HySnIewuw3rjgBlOc9sJMcrnQYdrb/EnJzLrcL4Sb4NmzB5gPW29vTc0Thkt4T4ghTCriOLCFjKihlc9sO8rsZ6fV10i/qfUONcrZYp1wVS18WOKQEBblgXp94L/Kl/mRVHFRicNDSVsZij9pHZovRprE3RkqO87qF67ZhcL3yzAVfkoRrWqDzG5PFpjGHLa3mV3nmL1vBKhL9/tkxbxz6svWkPYFSbxZx+JRSzzp3VPqFzSEiBmFNloCCVZfdSUMi5RlAD7r2NaCUR0+tXf0Io/YzXDuzMWk4Gq0FbJ+LWgfo1mXpj+iElmW4YS+oI6jyLVyQZEHZMvGcdiXyIZI76cdvqsjWL2C5e7O7p0ktTFmZfiBxHUUt3FbVZ+PqXk6H86uQ==

3. SSH Server에서 key를 read할 수 있도록 정책 설정

$ vi /vault/config/policy/ssh_policy.tf
path "ssh-client-signer/config/ca" {
  capabilities = ["read"]
}

4. SSH Server에서 key를 read할 수 있도록 정책 적용

$ cd /vault/config/policy/
$ vault policy write ssh-pubkey-read ssh_policy.tf
Success! Uploaded policy: ssh-pubkey-read

# SSH 정책 확인
$ vault policy list
default
ssh-pubkey-read

5. SSH Server에서 VAULT 서버로 접속할 Token 생성 → VAULT의 token값을 사용하기 위해서는 별도 저장 필요

$ vault token create -policy=ssh-pubkey-read
Key                        Value
---                         -----
token                     s.fX6YPfJI8xvi8NKZiI8O12UF
token_accessor       aUTigEQ0p2oNwoLUA8jMjWr6
token_duration       768h
token_renewable     true
token_policies         ["default" "ssh-pubkey-read"]
identity_policies      []
policies                   ["default" "ssh-pubkey-read"]

※ ssh-server에서 export 시켜주면 Vault 서버에서 SSH 인증서 public 키를 가져올 수 있음


6. SSH Client에서 Vault에 CA 사인 요청할 수 있도록 생성

  1. default_user
    • SSH 로그인에 사용될 유저 이름
    • default_user로 hippo 유저로 고정
    • 여러 사용자에 대해 허용할 것이라면 valid_principals 항목을 따로 정의해서 사용 필요
  1. ttl

    • CA가 사인한 키의 유효 기간을 의미

    • role을 통해 생성된 SSH 키는 5분 동안만 유효

      $ vault write ssh-client-signer/roles/my-role -<<"EOF"
      {
        "allow_user_certificates": true,
        "allowed_users": "*",
        "default_extensions": [
          {
            "permit-pty": ""
          }
        ],
        "key_type": "ca",
        "default_user": "hippo",
        "ttl": "5m0s"
      }
      EOF
      Success! Data written to: ssh-client-signer/roles/my-role

7. SSH Client에서 Vault에 CA 사인 update할 수 있도록 정책 설정

$ /vault/config/policy/
$ vi /vault/config/policy/sign_policy.tf
path "ssh-client-signer/sign/my-role" {
  capabilities = ["update"]
}

8. SSH Client에서 Vault에 CA 사인 update할 수 있도록 정책 적용

$ vault policy write require-ssh-sign sign_policy.tf
Success! Uploaded policy: require-ssh-sign

# 생성된 정책 확인
$ vault policy list
default
require-ssh-sign

9. SSH Client에서 VAULT 서버로 접속할 Token 생성 → VAULT의 token값을 사용하기 위해서는 별도 저장 필요

$ vault token create -policy=require-ssh-sign
Key                         Value
---                          -----
token                      s.HI8wvigrGvJuhUsk1H9ANmcl
token_accessor        0jom4yW0a8Nb4Cvw85NVCRtv
token_duration        768h
token_renewable      true
token_policies          ["default" "require-ssh-sign"]
identity_policies       []
policies                    ["default" "require-ssh-sign"]

※ ssh-client에서 export 시켜주면 Vault에서 CA 사인할 수 있는 public 키를 가져올 수 있음



SSH Server 설정 → SSH를 통해 접속하는 대상 서버

1. SSH Server에서 Vault server 접근할 수 있도록 환경변수 설정

  • VAULT_TOKEN 값은 SSH-Server에서 key를 read할 수 있도록 정책 설정 → s.fX6YPfJI8xvi8NKZiI8O12UF

  • VAULT 접속 도메인 설정 → [테스트 도메인]:8200

    # 환경 변수 적용
    export VAULT_ADDR=https://[테스트 도메인]:8200
    export VAULT_TOKEN=s.fX6YPfJI8xvi8NKZiI8O12UF
    
    # 영구적인 환경 변수 적용
    $ echo -e "\n#SSH\nexport VAULT_ADDR=https://[테스트 도메인]:8200" >> /etc/bashrc
    $ echo -e "export VAULT_TOKEN=s.fX6YPfJI8xvi8NKZiI8O12UF" >> /etc/bashrc

2. Vault server에서 CA의 public Key를 SSH Server에 전송

  • Vault server에서 public key 추출

      $ vault read -field=public_key ssh-client-signer/config/ca > /root/trusted-user-ca-keys.pem
    
      # 생성한 CA의 public key 확인
      $ cat /root/trusted-user-ca-keys.pem
      ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDALoH6ItfBjGnqNJAwFa1xUzOJ38WVosCNZQ3o2BlFJxhXvejU1CalDQDCZXEK8SIxeOqKC3mu/nIGMLYR5lwWRgl5r3janyLw8174MSM1wgSy9ZcURZrivicafKrH2WQAXJ6TKsrlhR5GODwxRCciD02l8LgbvaBs8pt1SRmvCc17xBAMuwu/A0pBU+tHotfiBqeLlQThi2mhpRSZ9u2cIt4neP/g+1/hMDxjlhmge7ehQBNYyWc2n8HDubCYT+z2GANk8vk6DhXs5iaLozM1lALXQZlbK3MpIVh1HySnIewuw3rjgBlOc9sJMcrnQYdrb/EnJzLrcL4Sb4NmzB5gPW29vTc0Thkt4T4ghTCriOLCFjKihlc9sO8rsZ6fV10i/qfUONcrZYp1wVS18WOKQEBblgXp94L/Kl/mRVHFRicNDSVsZij9pHZovRprE3RkqO87qF67ZhcL3yzAVfkoRrWqDzG5PFpjGHLa3mV3nmL1vBKhL9/tkxbxz6svWkPYFSbxZx+JRSzzp3VPqFzSEiBmFNloCCVZfdSUMi5RlAD7r2NaCUR0+tXf0Io/YzXDuzMWk4Gq0FbJ+LWgfo1mXpj+iElmW4YS+oI6jyLVyQZEHZMvGcdiXyIZI76cdvqsjWL2C5e7O7p0ktTFmZfiBxHUUt3FbVZ+PqXk6H86uQ==
    
      # scp를 통해 /etc/ssh 디렉토리 아래로 trusted-user-ca-keys.pem 파일 이동
      $ ls -al /etc/ssh/trusted-user-ca-keys.pem
      -rw-r--r-- 1 root root 725 Mar  1 17:39 /etc/ssh/trusted-user-ca-keys.pem

3. SSH 설정 → TrustedUserCAKeys /etc/ssh/trusted-user-ca-keys.pem 설정

$ vi /etc/ssh/sshd_config
Port 22000
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::

# TrustedUserCAKeys 추가
TrustedUserCAKeys /etc/ssh/trusted-user-ca-keys.pem

4. SSH 재시작 및 상태 확인

$ systemctl restart sshd

# 상태 확인
$ systemctl status sshd
● sshd.service - OpenSSH server daemon
   Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)
   Active: active (running) since Tue 2022-03-01 17:47:07 KST; 3s ago
     Docs: man:sshd(8)
           man:sshd_config(5)
 Main PID: 62539 (sshd)
    Tasks: 1
   Memory: 1.0M
   CGroup: /system.slice/sshd.service
           └─62539 /usr/sbin/sshd -D



SSH Client 설정 → SSH 서버에 접속하는 SSH 클라이언트 서버

1. SSH Client에서 Vault server 접근할 수 있도록 환경변수 설정

  • VAULT_TOKEN 값은 SSH-Client에서 Vault Server에 CA사인 요청할 수 있도록 정책 설정 → s.HI8wvigrGvJuhUsk1H9ANmcl

  • VAULT 접속 도메인 설정 → https://[테스트 도메인]:8200

      # 환경 변수 적용
      export VAULT_ADDR=https://[테스트 도메인]:8200
      export VAULT_TOKEN=s.HI8wvigrGvJuhUsk1H9ANmcl
    
      # 영구적인 환경 변수 적용
      echo -e "\n#SSH\nexport VAULT_ADDR=https://[테스트 도메인]:8200" >> /etc/bashrc
      echo -e "export VAULT_TOKEN=s.HI8wvigrGvJuhUsk1H9ANmcl" >> /etc/bashrc

2. SSH key 생성 → 모두 enter로 넘어감

$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:ubVlwjtNjjxM9xoOdw6h8rSTF+zGfTeGt64/E1FIUwU root@180-70-134-115
The key's randomart image is:
+---[RSA 2048]----+
|             .E++|
|              ...|
|                .|
|         o     . |
|        S =.*   .|
|         * &oo . |
|        o %+*o+ .|
|         +oB=B.*o|
|          o+o.B=*|
+----[SHA256]-----+

3. 생성한 key를 Vault server에 사인 요청하고 응답 결과 key를 저장

$ vault write -field=signed_key ssh-client-signer/sign/my-role public_key=@/root/.ssh/id_rsa.pub > /root/.ssh/id_rsa-cert.pub

# id_rsa.pub에 사인 요청을 해서 접속 확인
$ cat /root/.ssh/id_rsa-cert.pub
ssh-rsa-cert-v01@openssh.com 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

4. SSH Client 에서 SSH Server로 접속 확인 → 결과 정상 접속

$ ssh -p 22000 hippo@[SSH 접속 서버 IP]
Last login: Tue Mar  1 17:59:26 2022 from [SSH 클라이언트 서버 IP]

5. 5분뒤 접속 가능한지 확인 → Vault server에서 sign 유효 시간을 5분으로 설정

  • test하기 위해 5분 뒤에 생성했던 id_rsa-cert.pub로 접속 시도 → 실패

  • 인증서 서명 유효기간이 만료되어 password로 접속 시도 하는 것을 확인 → 직접 비밀번호를 모르기에 오류 발생

  • 새롭게 id_rsa-cert.pub을 생성한 후에 다시 로그인 시도

    $ ssh -p 22000 hippo@[SSH 접속 서버 IP]
    no such identity: /root/.ssh/id_ed25519: No such file or directory
    hippo@[SSH 접속 서버 IP]'s password:
    
    # 새롭게 인증서 만들어서 로그인 시도
    $ vault write -field=signed_key ssh-client-signer/sign/my-role public_key=@/root/.ssh/id_rsa.pub > /root/.ssh/id_rsa-cert.pub
    $ ssh -p 22000 hippo@[SSH 접속 서버 IP]
    Last login: Tue Mar  1 17:59:55 2022 from [SSH 클라이언트 서버 IP]

Vault audit log(감사 로그)를 /var/log/ 아래의 파일에 기록하도록 설정

  • /var/log/vault_audit.log 파일에 기록, 수정 가능
    $ vault audit enable file file_path=/var/log/vault_audit.log
    Success! Enabled the file audit device at: file/


Vault audit log(감사 로그) 리스트를 조회

  • audit 로그 생성 위치와 type을 확인 가능
    $ vault audit list
    Path     Type    Description
    ----      ----       -----------
    file/     file       n/a


생성된 /var/log/vault_audit.log 파일 내용 확인

  • vault server 동작 내용 확인 가능
    $ cat /var/log/vault_audit.log
    {"time":"2022-02-28T05:16:33.223325954Z","type":"request","auth":{"token_type":"default"},"request":{"id":"f95c9fd1-8414-5a4f-316c-0631b936e8f0","operation":"update","namespace":{"id":"root"},"path":"sys/audit/test"}}
    # [...생략...]

  • root token : s.asQ2M2u8kefJAH7pTRK9VZuY
  • sealing된 vault에는 루트 토큰(root token)으로도 로그인 불가

unseal된 Vault 서버에 로그인

$ vault login
Token (will be hidden):
WARNING! The VAULT_TOKEN environment variable is set! This takes precedence
over the value set by this command. To use the value set by this command,
unset the VAULT_TOKEN environment variable or set it to the token displayed
below.

Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.

Key                         Value
---                           -----
token                       s.asQ2M2u8kefJAH7pTRK9VZuY
token_accessor         DhyddellBSpndis790yPJCIp
token_duration         ∞
token_renewable       false
token_policies           ["root"]
identity_policies        []
policies                     ["root"]



Sealing된 상태에서 Vault 서버에 로그인 → 로그인 시 에러 발생

$ vault login
Token (will be hidden):
Error authenticating: error looking up token: Error making API request.

URL: GET https://[테스트 도메인]:8200/v1/auth/token/lookup-self
Code: 503. Errors:

* Vault is sealed

  • Vault 서버는 sealed(봉인) 상태로 시작 → sealed(봉인) 상태는 저장된 정보를 어떤 경우에도 평문으로 볼 수 없음
  • Vault 데이터를 암호화하여 저장하기에, Unsealing(개봉) 전에는 거의 모든 작업이 불가능
  • 암호화 키로 데이터를 암호화하고, 암호화 키는 키링에 보관하여 데이터와 함께 저장
  • 키링은 마스터 키로 알려진 다른 암호화 키로 암호화
  • Vault는 데이터를 복호화하기 위하여 먼저 암호화 키를 마스터 키를 이용하여 복호화 → Unsealing(복호화)는 마스터 키에 접근하는 프로세스
  • 마스터 키도 다른 모든 데이터와 함께 저장되지만 또 다른 메커니즘인 봉인해제 키(unseal key)에 의해 암호화

1. 데이터는 키링의 암호화 키로, 암호화 키는 마스터 키로, 마스터 키는 봉인해제 키로 암호화

"봉인해제 키 → 마스터 키 → 암호화 키 → 데이터"

2. Shamir’s Secret Sharing 샤미르의 비밀 공유

  • 봉인해제 키는 샤미르의 비밀 공유 알고리즘을 사용하여 여러 조각으로 분할되어 생성 (RSA에 'S'의 그 Shamir)
  • 각 봉인해제 키는 분리된 공간에 저장할 것을 권장
  • 봉인해제 시에 각 키를 입력 받아 임계치 이상의 키가 입력이 되면 봉인해제
  • Vault에서는 기본 값으로 5개의 키가 생성이 되고, 3개의 키가 입력되면 봉인해제


Unsealing(봉인해제)

  • Unsealing는 아래의 과정 중 하나를 통하여 수행
    1. 터미널에서 vault operator unseal 명령을 입력 후 Unsealing 키를 차례로 입력
    2. Unseal API 호출
    3. WebUI에서 키를 차례로 입력
  • Unsealing 상태에서 다시 sealing 상태가 되는 경우는 아래 중 하나의 방법으로 수행
    1. Seal API 호출
    2. Vault 서버 재시작
    3. Vault 저장소에서 복구할 수 없는 오류가 발생


Sealing(봉인)

  • sealing API를 호출하면 메모리에 있는 마스터 키가 폐기 → sealing 상태가 되면 vault를 사용하기 위해서 Unsealing 과정이 필요
  • sealing에는 루트 권한이 있는 단일 작업자만 필요
  • 침입이 감지되었을 때 Vault 데이터를 빠르게 잠가 피해를 최소화 가능


Vault server 초기화할 때 unseal key 발행

  • key-shares → 발행되는 unseal key 개수
  • key-threshold → 인증할 때 unseal key 사용 개수
  • key-shares와 key-threshold 옵션을 사용 X → 5개의 unseal key 발행되고, 그 중 3개를 입력해야 vault CLI 명령 사용 가능
  • vault 서버 초기화할 때는 vault 서버의 API를 설정 필요
    # VAULT_ADDR이 설정
    VAULT_ADDR='https://[테스트 도메인]:8200'

1. vault 서버 초기화

  • 5개의 unseal key 발행되고, 그 중 3개를 입력해야 VAULT 사용 가능

      # unseal key 발행
      $ vault operator init
      Unseal Key 1: ayPqZuzG7bBN3uRp/GYfUBIVg9MGrbIotnHrjYXNWQIm
      Unseal Key 2: iRntqlhFUfybvnjzLCHHxq/GQfDDtuPupxJyFqpLqpNc
      Unseal Key 3: ibTmbjiieSQPLB2ZnUNY2hrplvrr6ab1m8FnyY8moMMu
      Unseal Key 4: RdU4jDtYmAlF9bDFg8J3/l67Nph72ZFuyXlGWTzsP/ja
      Unseal Key 5: yO+uE3m3eCy/IgzU6qQFz4QC2mIlG6ZcVXC8ZH65u0Rr
    
      Initial Root Token: s.asQ2M2u8kefJAH7pTRK9VZuY
    
      Vault initialized with 5 key shares and a key threshold of 3. Please securely
      distribute the key shares printed above. When the Vault is re-sealed,
      restarted, or stopped, you must supply at least 3 of these keys to unseal it
      before it can start servicing requests.
    
      Vault does not store the generated master key. Without at least 3 keys to
      reconstruct the master key, Vault will remain permanently sealed!
    
      It is possible to generate new unseal keys, provided you have a quorum of
      existing unseal keys shares. See "vault operator rekey" for more information.

2. unseal키 수동 설정하여 vault 서버 초기화 (예시)

  • unseal 키 1개 설정하였으며, 1개의 unseal키를 입력하면 vault 서버 사용 가능

      # unseal key 발행
      $ vault operator init -key-shares=1 -key-threshold=1
    
      Unseal Key 1: 8vTbeSYOS0yWMve+NFy2eisJQkbqaPOb6ocp3zkHS1c=           # Unseal key 1개 발행 확인 -> 보관 필요
    
      Initial Root Token: s.s15mhZCNj4oOwcYji8TuIx5h                                        # Root Token 도 1개 발행 -> 보관 필요
    
      Vault initialized with 1 key shares and a key threshold of 1. Please securely
      distribute the key shares printed above. When the Vault is re-sealed,
      restarted, or stopped, you must supply at least 1 of these keys to unseal it
      before it can start servicing requests.
    
      Vault does not store the generated master key. Without at least 1 keys to
      reconstruct the master key, Vault will remain permanently sealed!
    
      It is possible to generate new unseal keys, provided you have a quorum of
      existing unseal keys shares. See "vault operator rekey" for more information.

3. vault 초기화 후 vault 서버 상태 확인

$ vault status
Key                       Value
---                        -----
Seal Type               shamir
Initialized               true
Sealed                   true
Total Shares           5                  # unseal 발행 개수
Threshold               3                  # unseal 인증 개수
Unseal Progress      0/3
Unseal Nonce         n/a
Version                  1.9.3
Storage Type          file
HA Enabled            false



Root Token인 VAULT_TOKEN을 환경 변수 지정

  • VAULT_TOKEN은 Vault를 초기화(init)할 때 root token이라고 획득 → s.asQ2M2u8kefJAH7pTRK9VZuY
  • Vault 서버의 루트 권한이 있는 토큰
    1. 서버의 모든 작업을 가능
    2. sealed 상태로 변경 가능
    3. unseal 상태로 변경은 불가능
  • vault 토큰은 VAULT_TOKEN 환경변수에 저장하면 vault 클라이언트에서 사용 가능

    # vault token을 환경 변수에 지정
    $ export VAULT_TOKEN=s.asQ2M2u8kefJAH7pTRK9VZuY
    $ echo -e "export VAULT_TOKEN=s.asQ2M2u8kefJAH7pTRK9VZuY" >> /root/.bashrc
    
    # VAULT에서 지정한 환경변수 확인
    $ env | grep -i vault
    VAULT_ADDR=https://[테스트 도메인]:8200
    VAULT_TOKEN=s.asQ2M2u8kefJAH7pTRK9VZuY



Vault Server를 unseal

  • vault init을 할 때 받은 unseal key를 입력 → 초기화할 때 발행받은 5개 중에 3개만 입력하면 됨
    1. 첫번째 : iRntqlhFUfybvnjzLCHHxq/GQfDDtuPupxJyFqpLqpNc
    2. 두번째 : ibTmbjiieSQPLB2ZnUNY2hrplvrr6ab1m8FnyY8moMMu
    3. 세번째 : RdU4jDtYmAlF9bDFg8J3/l67Nph72ZFuyXlGWTzsP/ja
  • 기본적으로 Vault server를 초기화하면 Sealed 상태가 됨 → 즉, 잠겨있어서 Vault 서버에서 정보를 읽는 등 작업 불가능
  • Vault server를 init에 알려준 Unseal Key를 이용하면 Unsealed 상태로 변경 → Vault 서버의 정보 읽기, 쓰기 등 여러 작업 가능

1. vault Server unseal (봉인 해제)

  • 3번의 vault operator unseal을 통해 봉인 해제

  • unseal 명령어를 성공할 때마다 Unseal Progress의 수치가 올라가서 3/3이 되었을 때 unseal이 됨

  • unseal이 완료 → Sealed : false

    # 첫번째 Vault unseal
    $ vault operator unseal
    Unseal Key (will be hidden):
    Key                Value
    ---                -----
    Seal Type          shamir
    Initialized        true
    Sealed             true
    Total Shares       5
    Threshold          3
    Unseal Progress    1/3
    Unseal Nonce       ccbf047b-5956-fdd8-29f9-bad6969cdd45
    Version            1.9.3
    Storage Type       file
    HA Enabled         false
    
    # 두번째 Vault unseal
    $ vault operator unseal
    Unseal Key (will be hidden):
    Key                Value
    ---                -----
    Seal Type          shamir
    Initialized        true
    Sealed             true
    Total Shares       5
    Threshold          3
    Unseal Progress    2/3
    Unseal Nonce       ccbf047b-5956-fdd8-29f9-bad6969cdd45
    Version            1.9.3
    Storage Type       file
    HA Enabled         false
    
    # 세번째 Vault unseal
    $ vault operator unseal
    Unseal Key (will be hidden):
    Key             Value
    ---             -----
    Seal Type       shamir
    Initialized     true
    Sealed          false
    Total Shares    5
    Threshold       3
    Version         1.9.3
    Storage Type    file
    Cluster Name    vault-cluster-0b89b3d2
    Cluster ID      dbea1671-61fa-c4c8-387e-e32390ace762
    HA Enabled      false

※ unseal 참고 사항

  • 연속적으로 unseal을 3번 실행하여 Vault 서버를 열 수 있다.
  • 하지만, 한사람이 unseal key를 다 가지는 것은 위험 → 키를 5명이 나누어 갖고 3명이 unseal을 하면 Vault 서버를 엶
  • Vault에 중요한 정보가 있음으로 서버를 재시작하거나 보안 문제 발생으로 sealed 상태로 바꾸었을 때, 다시 서버를 열려면 unseal 단계를 거쳐야 함
  • unseal 과정은 서버가 기억하고 있으므로 한자리에 모일 필요 없이 각자의 자리에서 unseal을 하기만 하면 됨
  • unseal은 시간 제한도 없기에 충분히 시간을 두고 진행 가능
  • 스토리지 백엔드에도 암호화된 정보가 저장되어 있고, 복호화하려면 unseal 단계가 필수적 → unseal 키 3개가 없으면 Vault 서버도 복호화키도 만들어 낼 수 없음
  • DB가 통째로 털려도 Vault 서버가 통째로 털려도 unseal 키 3개가 없다면 공격자는 정보를 볼 수 없게 되어 안전함

2. unseal할 때 출력한 vault server 상태와 vault status 명령어로 출력되는 상태가 같은 지 확인

  • vault server가 unseal됨 → token을 입력해야 서버 내부 접근 가능

    $ vault status
    Key                 Value
    ---                   -----
    Seal Type         shamir
    Initialized         true
    Sealed             false
    Total Shares      5
    Threshold         3
    Version             1.9.3
    Storage Type     file
    Cluster Name    vault-cluster-0b89b3d2
    Cluster ID         dbea1671-61fa-c4c8-387e-e32390ace762
    HA Enabled       false



Vault Server를 Sealing

  • vault를 서버에 보안 문제가 있거나, 안전하게 관리하기 위해서 unsealing되어있는 것을 sealing으로 변경

      $ vault operator seal
      Success! Vault is sealed.
  • 다시 sealing된 vault 서버의 상태 확인

      $ vault status
      Key                    Value
      ---                   -----
      Seal Type          shamir
      Initialized          true
      Sealed               true
      Total Shares        5
      Threshold           3
      Unseal Progress     0/3
      Unseal Nonce       n/a
      Version               1.9.3
      Storage Type        file
      HA Enabled          false

  • systemd 서비스 사용하여 vault 서버 구축
  • Vault 실 서버에 사용할 도메인 및 인증서 필요
  • VAult 관련 참고 URL : https://www.vaultproject.io/docs

Valut 설치 및 systemd로 서비스 관리

1. Vault 설치 및 패키지 버전 확인

$ yum install -y yum-utils
$ yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
$ yum -y install vault

2. 설치한 vault 패키지 버전 확인

$ vault version
Vault v1.9.3 (7dbdd57243a0d8d9d9e07cd01eb657369f8e1b8a)

3. Vault 서비스를 systemd로 관리

$ vi /etc/systemd/system/vault.service
[Unit]
Description=Vault secret store
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
ExecStart=/usr/bin/vault server -config=/vault/config/vault-config.hcl
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target



Vault 서버 실행

  • vault를 다운받게 되면 기본적으로 /opt/vault/ 디렉토리 아래에 있는 data 디렉토리와 tls 디렉토리 생성
  • data 디렉토리는 Vault 데이터가 저장되는 공간
  • tls 디렉토리는 Vault의 https를 사용하기 위한 인증서 키가 있는 공간 → https를 사용할 인증서 설치 필요
  • /vault/ 디렉토리 data 디렉토리와 tls 디렉토리 복사 필요

1. Vault config 적용 → https://[Vault 서버 도메인]:8200

  • Vault Server는 configuration file을 통해서 configuration을 얻음.

  • vault-config.hcl 이름을 가진 configuration 파일을 통해서 Vault Server에서 사용할 configuration 확인 가능

  • 기본 Vault 서버의 API를 사용하는 주소를 설정 → VAULT_ADDR=’https://[Vault 서버 도메인]:8200’

  • vault-config.hcl을 생성하기 윈한 내용 참고 URL : https://www.vaultproject.io/docs/configuration

    $ mkdir /vault
    $ cp -r /opt/vault/* /vault/
    $ ls /vault/
    data  tls
    
    $ mkdir /vault/config/
    
    # vault-config를 설정할 hcl 생성
    $ vi /vault/config/vault-config.hcl
    # ui 사용 허가
    ui = true
    
    # Vault 데이터가 저장되는 스토리지 백엔드를 구성
    storage "file" {
    path = "/vault/data"
    }
    
    # API 서버의 IP와 PORT 선언
    api_addr = "https://[Vault 서버 도메인]:8200"
    
    # HTTP listener -> HTTP 사용 X
    #listener "tcp" {
    #  address = "0.0.0.0:8200"
    #  tls_disable = 1
    #}
    
    # HTTPS listener -> HTTPS 사용
    listener "tcp" {
    address       = "0.0.0.0:8200"
    tls_cert_file = "/vault/tls/tls.crt"
    tls_key_file  = "/vault/tls/tls.key"
    }
    
    # 기본 VAULT_ADDR은 "https://127.0.0.1:8200"으로 되어있기에 vault 서버의 API를 사용하는 주소를 설정 
    # VAULT_ADDR='https://[Vault 서버 도메인]:8200'
    $ export VAULT_ADDR='https://[Vault 서버 도메인]:8200'
    $ echo -e "export VAULT_ADDR='https://[Vault 서버 도메인]:8200'" >> /root/.bashrc
    $ echo $VAULT_ADDR
    https://[Vault 서버 도메인]:8200

2. vault.service를 재시작하여 설정 적용

$ systemctl daemon-reload
$ systemctl start vault.service
$ systemctl status vault
● vault.service - Vault secret store
   Loaded: loaded (/etc/systemd/system/vault.service; disabled; vendor preset: disabled)
   Active: active (running) since Sun 2022-02-27 16:42:28 KST; 24s ago
 Main PID: 14832 (vault)
   CGroup: /system.slice/vault.service
           └─14832 /usr/bin/vault server -config=/vault/config/vault-config.hcl

3. config 설정을 적용한 vault 서버가 정상적으로 실행되는 지 확인 → API

# jq 패키지 설치
$ yum install -y jq


# 외부에서 https://[Vault 서버 도메인]:8200 도메인 요청하여  vault server에게 API 성공 확인
$ curl https://[Vault 서버 도메인]:8200/v1/sys/seal-status | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   168  100   168    0     0     29      0  0:00:05  0:00:05 --:--:--    40
{
  "type": "shamir",
  "initialized": false,
  "sealed": true,
  "t": 0,
  "n": 0,
  "progress": 0,
  "nonce": "",
  "version": "1.9.3",
  "migration": false,
  "recovery_seal": false,
  "storage_type": "file"
}

4. config 설정을 적용한 vault 서버에 status 확인

# vault 서버에서 vault status 명령어 확인
$ vault status
Key                     Value
---                      -----
Seal Type            shamir
Initialized            false
Sealed                 true
Total Shares         0
Threshold             0
Unseal Progress    0/0
Unseal Nonce        n/a
Version                1.9.3
Storage Type        file
HA Enabled          false



Vault UI 웹페이지 Open

  1. https://[Vault 서버 도메인]:8200으로 접속
  2. 아직 Unseal을 하지 않았기 때문에 접근은 불가능 → unseal을 하면 웹 페이지 안에 접근 가능

  • 토큰, 비밀번호, 인증서, 암호화 키와 같은 비밀 정보나 민감한 데이터를 UI, CLI, HTTP API 를 활용할때 안전하게 저장하고 제어할수 있게 해주는 오픈 소스
  • vault 메뉴얼 URL : https://www.vaultproject.io/

Valut 설치

$ yum install -y yum-utils
$ yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
$ yum -y install vault

# 설치한 vault 패키지 버전 확인
$ vault -v
Vault v1.8.0 (82a99f14eb6133f99a975e653d4dac21c17505c7)



Vault server를 DEV 모드로 실행

1. 환경변수 등록

  • vault CLI 를 사용하기 위해 환경변수 등록이 필요

      # 수동으로 환경 변수 등록
      $ export VAULT_ADDR='http://127.0.0.1:8200'
    
      # 영구적으로 환경 변수 등록
      $ echo "export VAULT_ADDR='http://127.0.0.1:8200'" >> /root/.bashrc
      $ source /root/.bashrc
    
      # 설정 확인
      $ echo $VAULT_ADDR
      http://127.0.0.1:8200

2. 테스트를 위해 -dev 모드로 백그라운드에서 서버를 실행

  • dev모드는 미리 준비된 설정으로 서버를 구동

  • dev 모드는 모든 데이터는 in-memory 저장, 암호화

  • localhost로 listen되며 TLS가 없음

  • 자동 봉인 해제 → 봉인 해제된 키와 엑세스 토큰을 보여줌

  • 프로덕션 모드에서는 -dev 옵션 사용을 권장 X

    $ vault server -dev &
    ==> Vault server configuration:
    
               Api Address: http://127.0.0.1:8200
                       Cgo: disabled
           Cluster Address: https://127.0.0.1:8201
                Go Version: go1.16.5
                Listener 1: tcp (addr: "127.0.0.1:8200", cluster address: "127.0.0.1:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled")
                 Log Level: info
                     Mlock: supported: true, enabled: false
             Recovery Mode: false
                   Storage: inmem
                   Version: Vault v1.8.0
               Version Sha: 82a99f14eb6133f99a975e653d4dac21c17505c7
    
    ==> Vault server started! Log data will stream in below:
    
    2021-08-02T14:07:10.555Z [INFO]  proxy environment: http_proxy="" https_proxy="" no_proxy=""
    2021-08-02T14:07:10.556Z [WARN]  no `api_addr` value specified in config or in VAULT_API_ADDR; falling back to detection if possible, but this value should be manually set
    2021-08-02T14:07:10.557Z [INFO]  core: security barrier not initialized
    2021-08-02T14:07:10.557Z [INFO]  core: security barrier initialized: stored=1 shares=1 threshold=1
    2021-08-02T14:07:10.558Z [INFO]  core: post-unseal setup starting
    2021-08-02T14:07:10.572Z [INFO]  core: loaded wrapping token key
    2021-08-02T14:07:10.572Z [INFO]  core: successfully setup plugin catalog: plugin-directory=""
    2021-08-02T14:07:10.572Z [INFO]  core: no mounts; adding default mount table
    2021-08-02T14:07:10.573Z [INFO]  core: successfully mounted backend: type=cubbyhole path=cubbyhole/
    2021-08-02T14:07:10.574Z [INFO]  core: successfully mounted backend: type=system path=sys/
    2021-08-02T14:07:10.574Z [INFO]  core: successfully mounted backend: type=identity path=identity/
    2021-08-02T14:07:10.582Z [INFO]  core: successfully enabled credential backend: type=token path=token/
    2021-08-02T14:07:10.589Z [INFO]  core: restoring leases
    2021-08-02T14:07:10.603Z [INFO]  rollback: starting rollback manager
    2021-08-02T14:07:10.603Z [INFO]  expiration: lease restore complete
    2021-08-02T14:07:10.604Z [INFO]  identity: entities restored
    2021-08-02T14:07:10.604Z [INFO]  identity: groups restored
    2021-08-02T14:07:10.604Z [INFO]  core: post-unseal setup complete
    2021-08-02T14:07:10.604Z [INFO]  core: root token generated
    2021-08-02T14:07:10.604Z [INFO]  core: pre-seal teardown starting
    2021-08-02T14:07:10.604Z [INFO]  rollback: stopping rollback manager
    2021-08-02T14:07:10.604Z [INFO]  core: pre-seal teardown complete
    2021-08-02T14:07:10.604Z [INFO]  core.cluster-listener.tcp: starting listener: listener_address=127.0.0.1:8201
    2021-08-02T14:07:10.604Z [INFO]  core.cluster-listener: serving cluster requests: cluster_listen_address=127.0.0.1:8201
    2021-08-02T14:07:10.604Z [INFO]  core: post-unseal setup starting
    2021-08-02T14:07:10.605Z [INFO]  core: loaded wrapping token key
    2021-08-02T14:07:10.605Z [INFO]  core: successfully setup plugin catalog: plugin-directory=""
    2021-08-02T14:07:10.605Z [INFO]  core: successfully mounted backend: type=system path=sys/
    2021-08-02T14:07:10.605Z [INFO]  core: successfully mounted backend: type=identity path=identity/
    2021-08-02T14:07:10.605Z [INFO]  core: successfully mounted backend: type=cubbyhole path=cubbyhole/
    2021-08-02T14:07:10.606Z [INFO]  core: successfully enabled credential backend: type=token path=token/
    2021-08-02T14:07:10.606Z [INFO]  core: restoring leases
    2021-08-02T14:07:10.607Z [INFO]  identity: entities restored
    2021-08-02T14:07:10.607Z [INFO]  identity: groups restored
    2021-08-02T14:07:10.607Z [INFO]  core: post-unseal setup complete
    2021-08-02T14:07:10.607Z [INFO]  core: vault is unsealed
    2021-08-02T14:07:10.609Z [INFO]  core: successful mount: namespace="" path=secret/ type=kv
    2021-08-02T14:07:10.610Z [INFO]  expiration: lease restore complete
    2021-08-02T14:07:10.610Z [INFO]  secrets.kv.kv_f71fab5a: collecting keys to upgrade
    2021-08-02T14:07:10.610Z [INFO]  secrets.kv.kv_f71fab5a: done collecting keys: num_keys=1
    2021-08-02T14:07:10.610Z [INFO]  secrets.kv.kv_f71fab5a: upgrading keys finished
    2021-08-02T14:07:10.611Z [INFO]  rollback: starting rollback manager
    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 variable:
    
      $ 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: +1P8t1jNPI8mBPCV57v+emB4E3DttH3t1xkz+oXsQUs=
    Root Token: s.BT8kE324DT9EJYQqG8noC8J1
    
    Development mode should NOT be used in production installations!

3. 실행된 서버의 상태를 확인

$ vault status
Key                   Value
---                    -----
Seal Type          shamir
Initialized          true
Sealed              false
Total Shares      1
Threshold          1
Version             1.3.0
Cluster Name    vault-cluster-a6999d5c
Cluster ID         291371dc-e6a5-42d3-fca7-b2373ff70194
HA Enabled       false



vault 와 secret

  • vault의 핵심 기능중 하나는 비밀정보를 안전하게 읽고 쓰는것
  • vault에 기록된 비밀정보는 암호화하여 backend 저장소에 저장
  • 값을 저장소에 전달하기 전에 암호화를 하며, backend 저장소에 저장된 암호화값은 vault 없이는 해독 불가능



write a secret (비밀정보 작성)

  • key 값의 접두사가 secret/ 로 저장됨

  • secret/ 는 어떤 secrets engine을 실행시킬지 결정하는 route 역할(경로 결정)

  • 비밀정보를 기록할때는 shell history에 남기때문에 되도록이면 file 을 통해서 전달될수있도록 하는것이 좋음

  • kv → Vault의 키-값 저장소와 상호작용 (command)

  • put → KV 저장소의 데이터를 설정하거나 업데이트함

  • secret/hello → hello 이름을 가지는 secret engine 사용

  • foo=world → foo 키에 world 값이 있음

    $ vault kv put secret/hello foo=world
    Key                     Value
    ---                       -----
    created_time        2021-08-02T15:40:03.164784248Z
    deletion_time        n/a
    destroyed             false
    version                1



read a secret (비밀정보 읽기)

1. secret과 함께 여러 가지 메타 데이터가 함께 반환

  • 비밀정보를 획득

  • vault는 저장소로부터 값을 가져올때 복호화하여 가져옴

  • kv → Vault의 키-값 저장소와 상호작용 (command)

  • get → KV 저장소에서 데이터 검색

  • secret/hello → hello 이름을 가지는 secret engine 사용

    $ vault kv get secret/hello
    ====== Metadata ======
    Key Value
    --- -----
    created_time 2019-11-26T02:39:20.8458832Z
    deletion_time n/a
    destroyed false
    version 1
    
    === Data ===
    Key Value
    --- -----
    foo world

2. hello 키에 해당하는 값 추출

  • kv → Vault의 키-값 저장소와 상호작용 (command)

  • get → KV 저장소에서 데이터 검색

  • field=key → 입력한 key의 value를 출력, -field 옵션을 사용하면 다른 형식 지정 지시문보다 우선

    $ vault kv get -field=foo secret/hello
    world

3. JSON output → 결과데이터의 포맷을 json형식으로 출력

  • kv → Vault의 키-값 저장소와 상호작용 (command)

  • get → KV 저장소에서 데이터 검색

  • format=형식 → "table", "json", "yaml", "pretty" 중에 입력한 형식으로 출력 → 기본값은 table로 출력

  • format 옵션을 사용하지 않고, VAULT_FORMAT 환경 변수를 통해 지정 가능

    $ vault kv get -format=json secret/hello
    {
    "request_id": "777069c4-4cb8-1bfa-2eaa-5d35018eca54",
    "lease_id": "",
    "lease_duration": 0,
    "renewable": false,
    "data": {
      "data": {
        "foo": "world"
      },
      "metadata": {
        "created_time": "2021-08-02T15:40:03.164784248Z",
        "deletion_time": "",
        "destroyed": false,
        "version": 1
      }
    },
    "warnings": null
    }

4. jq 활용 → jq 도구를 통해 더 편리하게 원하는 메타정보를 가져올 수 있음

  • kv → Vault의 키-값 저장소와 상호작용 (command)

  • get → KV 저장소에서 데이터 검색

  • format=json → json 형식으로 출력

  • json 형식으로 출력되면 key값으로 해서 해당 value를 찾을 수 있음

    # jq를 사용하기 위해서는 패키지 설치 필요
    $ yum install -y jq
    
    #  data 키 → data 키 → foo 키의 값 출력
    $ vault kv get -format=json secret/hello | jq -r .data.data.foo
    world



delete a secret (비밀정보 삭제)

  • 저장된 비밀정보를 삭제

  • kv → Vault의 키-값 저장소와 상호작용 (command)

  • delete → KV 저장소에서 데이터 삭제

    $ vault kv delete secret/hello
    Success! Data deleted (if it existed) at: secret/hello
    
    # key와 value가 삭제됨을 확인
    $ vault kv get secret/hello
    ====== Metadata ======
    Key                      Value
    ---                       -----
    created_time        2021-08-02T15:40:03.164784248Z
    deletion_time       2021-08-02T16:17:00.129797593Z
    destroyed             false
    version                1

+ Recent posts