다음을 통해 공유


사이드카 컨테이너에서 Caddy로 자동 HTTPS 사용

이 문서에서는 Caddy를 컨테이너 그룹의 사이드카 컨테이너로 사용하고 역방향 프록시 역할을 하여 애플리케이션에 자동으로 관리되는 HTTPS 엔드포인트를 제공하는 방법을 설명합니다.

Caddy는 Go로 작성된 자동 HTTPS를 갖춘 강력하고 엔터프라이즈급 오픈 소스 웹 서버이며 Nginx의 대안을 제시합니다.

Caddy는 Let's Encrypt와 상호 작용하여 인증서를 발급하는 ACMEv2 API(RFC 8555)를 지원하므로 인증서 자동화가 가능합니다.

이 예제에서는 Caddy 컨테이너만 포트 80/TCP 및 443/TCP에 노출됩니다. 역방향 프록시 뒤에 있는 애플리케이션은 비공개로 유지됩니다. Caddy와 애플리케이션 간의 네트워크 통신은 localhost를 통해 수행됩니다.

참고 항목

이는 컨테이너를 이름으로 참조할 수 있는 docker compose에서 알려진 컨테이너 그룹 내 통신과는 대조적입니다.

이 예제에서는 Azure Storage 계정에 호스트된 파일 공유에서 역방향 프록시를 구성하는 데 필요한 Caddyfile을 탑재합니다.

참고 항목

프로덕션 배포의 경우 대부분의 사용자는 캐디을 기반으로 Caddyfile을 사용자 지정 Docker 이미지로 베이킹하려고 합니다. 이렇게 하면 컨테이너에 파일을 탑재할 필요가 없습니다.

사전 요구 사항

  • 이 문서대로 하려면 Azure CLI 버전 2.0.55 이상이 필요합니다. Azure Cloud Shell을 사용하는 경우 최신 버전이 이미 설치되어 있습니다.

Caddyfile 준비

Caddyfile이라는 파일을 만들고 다음 구성을 붙여넣습니다. 이 구성은 5000/TCP에서 수신 대기하는 애플리케이션 컨테이너를 가리키는 역방향 프록시 구성을 만듭니다.

my-app.westeurope.azurecontainer.io {
    reverse_proxy http://localhost:5000
}

구성이 IP 주소 대신 도메인 이름을 참조한다는 점에 유의해야 합니다. ACME 프로토콜에 필요한 챌린지 단계를 수행하고 Let's Encrypt에서 인증서를 성공적으로 검색하려면 이 URL을 통해 Caddy에 연결할 수 있어야 합니다.

참고 항목

프로덕션 배포의 경우 사용자는 제어하는 도메인 이름(예: api.company.com)을 사용하고 예를 들어 my-app.westeurope.azurecontainer.io를 가리키는 CNAME 레코드를 만들 수 있습니다. 그렇다면 사용자 지정 도메인 이름이 Azure에서 할당한 이름(예: *.westeurope.azurecontainer.io) 대신 Caddyfile에서도 사용되도록 해야 합니다. 또한 사용자 지정 도메인 이름은 이 예제의 뒷부분에 설명된 ACI YAML 구성에서 참조되어야 합니다.

스토리지 계정 준비

저장소 계정 만들기

az storage account create \
  --name <storage-account> \
  --resource-group <resource-group> \
  --location westeurope

환경 변수에 연결 문자열 저장

AZURE_STORAGE_CONNECTION_STRING=$(az storage account show-connection-string --name <storage-account> --resource-group <resource-group> --output tsv)

컨테이너 상태 및 캐디 구성을 저장하는 데 필요한 파일 공유를 만듭니다.

az storage share create \
  --name proxy-caddyfile \
  --account-name <storage-account>

az storage share create \
  --name proxy-config \
  --account-name <storage-account>
  
  az storage share create \
  --name proxy-data \
  --account-name <storage-account>

스토리지 계정 키를 검색하고 나중에 사용할 수 있도록 기록해 둡니다.

az storage account keys list -g <resource-group> -n <storage-account>

컨테이너 그룹 배포

YAML 파일 만들기

ci-my-app.yaml이라는 파일을 만들고 다음 콘텐츠를 붙여넣습니다. <account-key>를 이전에 받은 액세스 키 중 하나로 바꾸고 그에 따라 <storage-account>를 바꿉니다.

이 YAML 파일은 두 개의 컨테이너 reverse-proxymy-app을 정의합니다. reverse-proxy 컨테이너는 이전에 만든 세 개의 파일 공유를 탑재합니다. 또한 구성은 reverse-proxy 컨테이너의 포트 80/TCP 및 443/TCP를 노출합니다. 두 컨테이너 간의 통신은 localhost에서만 발생합니다.

참고 항목

dnsNameLabel 키는 컨테이너 인스턴스 그룹에 연결할 수 있는 공용 DNS 이름을 정의하며 Caddyfile에 정의된 FQDN과 일치해야 합니다.

name: ci-my-app
apiVersion: "2021-10-01"
location: westeurope
properties:
  containers:
    - name: reverse-proxy
      properties:
        image: caddy:2.6
        ports:
          - protocol: TCP
            port: 80
          - protocol: TCP
            port: 443
        resources:
          requests:
            memoryInGB: 1.0
            cpu: 1.0
          limits:
            memoryInGB: 1.0
            cpu: 1.0
        volumeMounts:
          - name: proxy-caddyfile
            mountPath: /etc/caddy
          - name: proxy-data
            mountPath: /data
          - name: proxy-config
            mountPath: /config
    - name: my-app
      properties:
        image: mcr.microsoft.com/azuredocs/aci-helloworld
        ports:
        - port: 5000
          protocol: TCP
        environmentVariables:
        - name: PORT
          value: 5000
        resources:
          requests:
            memoryInGB: 1.0
            cpu: 1.0
          limits:
            memoryInGB: 1.0
            cpu: 1.0
  ipAddress:
    ports:
      - protocol: TCP
        port: 80
      - protocol: TCP
        port: 443
    type: Public        
    dnsNameLabel: my-app
  osType: Linux
  volumes:
    - name: proxy-caddyfile
      azureFile: 
        shareName: proxy-caddyfile
        storageAccountName: "<storage-account>" 
        storageAccountKey: "<account-key>"
    - name: proxy-data
      azureFile: 
        shareName: proxy-data
        storageAccountName: "<storage-account>"  
        storageAccountKey: "<account-key>"
    - name: proxy-config
      azureFile: 
        shareName: proxy-config
        storageAccountName: "<storage-account>"  
        storageAccountKey: "<account-key>"

컨테이너 그룹 배포

az group create 명령을 사용하여 리소스 그룹을 만듭니다.

az group create --name <resource-group> --location westeurope

az container create 명령을 사용하여 컨테이너 그룹을 배포하고, YAML 파일을 인수로 전달합니다.

az container create --resource-group <resource-group> --file ci-my-app.yaml

배포 상태 보기

배포 상태를 확인하려면 다음 az container show 명령을 사용합니다.

az container show --resource-group <resource-group> --name ci-my-app --output table

TLS 연결 확인

모든 것이 제대로 진행되었는지 확인하기 전에 컨테이너 그룹이 완전히 시작하고 Caddy가 인증서를 요청할 시간을 줍니다.

OpenSSL

이를 위해 OpenSSL의 s_client 하위 명령을 사용할 수 있습니다.

echo "Q" | openssl s_client -connect my-app.westeurope.azurecontainer.io:443
CONNECTED(00000188)
---
Certificate chain
 0 s:CN = my-app.westeurope.azurecontainer.io
   i:C = US, O = Let's Encrypt, CN = R3
 1 s:C = US, O = Let's Encrypt, CN = R3
   i:C = US, O = Internet Security Research Group, CN = ISRG Root X1
 2 s:C = US, O = Internet Security Research Group, CN = ISRG Root X1
   i:O = Digital Signature Trust Co., CN = DST Root CA X3
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIEgTCCA2mgAwIBAgISAxxidSnpH4vVuCZk9UNG/pd2MA0GCSqGSIb3DQEBCwUA
MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD
EwJSMzAeFw0yMzA0MDYxODAzMzNaFw0yMzA3MDUxODAzMzJaMC4xLDAqBgNVBAMT
I215LWFwcC53ZXN0ZXVyb3BlLmF6dXJlY29udGFpbmVyLmlvMFkwEwYHKoZIzj0C
AQYIKoZIzj0DAQcDQgAEaaN/wGyFcimM+1O4WzbFgO6vIlXxXqp9vgmLZHpFrNwV
aO8JbaB7hE+M5EAg34LDY80RyHgY+Ff4vTh2Z96rVqOCAl4wggJaMA4GA1UdDwEB
/wQEAwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/
BAIwADAdBgNVHQ4EFgQUoL5DP+4PWiyE79hL5o+v8uymHdAwHwYDVR0jBBgwFoAU
FC6zF7dYVsuuUAlA5h+vnYsUwsYwVQYIKwYBBQUHAQEESTBHMCEGCCsGAQUFBzAB
hhVodHRwOi8vcjMuby5sZW5jci5vcmcwIgYIKwYBBQUHMAKGFmh0dHA6Ly9yMy5p
LmxlbmNyLm9yZy8wLgYDVR0RBCcwJYIjbXktYXBwLndlc3RldXJvcGUuYXp1cmVj
b250YWluZXIuaW8wTAYDVR0gBEUwQzAIBgZngQwBAgEwNwYLKwYBBAGC3xMBAQEw
KDAmBggrBgEFBQcCARYaaHR0cDovL2Nwcy5sZXRzZW5jcnlwdC5vcmcwggEEBgor
BgEEAdZ5AgQCBIH1BIHyAPAAdgC3Pvsk35xNunXyOcW6WPRsXfxCz3qfNcSeHQmB
Je20mQAAAYdX8+CQAAAEAwBHMEUCIQC9Ztqd3DXoJhOIHBW+P7ketGrKlVA6nPZl
9CiOrn6t8gIgXHcrbBqItemndRMv+UJ3DaBfTkYOqECecOJCgLhSYNUAdgDoPtDa
PvUGNTLnVyi8iWvJA9PL0RFr7Otp4Xd9bQa9bgAAAYdX8+CAAAAEAwBHMEUCIBJ1
24z44vKFUOLCi1a7ymVuWErkmLb/GtysvcxILaj0AiEAr49hyKfen4BbSTwC8Fg4
/LgZnn2F3uHI+9p+ZMO9xTAwDQYJKoZIhvcNAQELBQADggEBACqxa21eiW3JrZwk
FHgpd6SxhUeecrYXxFNva1Y6G//q2qCmGeKK3GK+ZGPqDtcoASH5t5ghV4dIT4WU
auVDLFVywXzR8PT6QUu3W8QxU+W7406twBf23qMIgrF8PIWhStI5mn1uCpeqlnf5
HpRaj2f5/5n19pcCZcrRx94G9qhPYdMzuy4mZRhxXRqrpIsabqX3DC2ld8dszCvD
pkV61iuARgm3MIQz1yL/x5Bn4nywjnhYZA4KFktC0Ti55cPRh1mkzGQAsYQDdWrq
dVav+U9dOLQ4Sq4suaDmzDzApr+hpQSJhwgRN16+tLMyZ6INAU2JWKDxiyDTdOuH
jz456og=
-----END CERTIFICATE-----
subject=CN = my-app.westeurope.azurecontainer.io

issuer=C = US, O = Let's Encrypt, CN = R3

---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: ECDSA
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 4208 bytes and written 401 bytes
Verification error: unable to get local issuer certificate
---
New, TLSv1.3, Cipher is TLS_AES_128_GCM_SHA256
Server public key is 256 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 20 (unable to get local issuer certificate)
---
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_128_GCM_SHA256
    Session-ID: 85F1A4290F99A0DD28C8CB21EF4269E7016CC5D23485080999A8548057729B24
    Session-ID-ctx: 
    Resumption PSK: 752D438C19A5DBDBF10781F863D5E5D9A8859230968A9EAFFF7BBA86937D004F
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 604800 (seconds)
    TLS session ticket:
    0000 - 2f 25 98 90 9d 46 9b 01-03 78 db bd 4d 64 b3 a6   /%...F...x..Md..
    0010 - 52 c0 7a 8a b6 3d b8 4b-c0 d7 fc 04 e8 63 d4 bb   R.z..=.K.....c..
    0020 - 15 b3 25 b7 be 64 3d 30-2b d7 dc 7a 1a d1 22 63   ..%..d=0+..z.."c
    0030 - 42 30 90 65 6b b5 e1 83-a3 6c 76 c8 f6 ae e9 31   B0.ek....lv....1
    0040 - 45 91 33 57 8e 9f 4b 6a-2e 2c 9b f9 87 5f 71 1d   E.3W..Kj.,..._q.
    0050 - 5a 84 59 50 17 31 1f 62-2b 0e 1e e5 70 03 d9 e9   Z.YP.1.b+...p...
    0060 - 50 1c 5d 1f a4 3c 8a 0e-f4 c5 7d ce 9e 5c 98 de   P.]..<....}..\..
    0070 - e5                                                .

    Start Time: 1680808973
    Timeout   : 7200 (sec)
    Verify return code: 20 (unable to get local issuer certificate)
    Extended master secret: no
    Max Early Data: 0
---
read R BLOCK

Chrome 브라우저

https://my-app.westeurope.azurecontainer.io로 이동해 URL 옆에 있는 자물쇠를 클릭하여 인증서를 확인합니다.

인증서를 확인하는 URL 옆에 있는 자물쇠를 강조 표시한 스크린샷.

인증서 세부 정보를 보려면 "연결이 안전합니다"를 선택한 다음 "인증서가 유효합니다"를 선택합니다.

Let's Encrypt에서 발급한 인증서의 스크린샷.

다음 단계