Istio Ingress Gateway (2)
December 24, 2022 교육 v1.0Istio의 Ingress Gateway 실습 두번째 파트입니다. (실습1에서 이어집니다)
Securing gateway traffic
HTTPS 통신하기
Serect 생성 - 서버 인증서 저장
kubectl create -n istio-system secret tls webapp-credential \
--key ch4/certs/3_application/private/webapp.istioinaction.io.key.pem \
--cert ch4/certs/3_application/certs/webapp.istioinaction.io.cert.pem
## Secret 생성 확인
# kubectl get secret webapp-credential -n istio-system
NAME TYPE DATA AGE
webapp-credential kubernetes.io/tls 2 47s
(참고) Secret에 저장된 인증서를 확인해 봐요
- Issuer 는 발급처(CA)를 의미합니다.
- Validity 는 인증서 유효기간 입니다.
- Subject 는 발급받은 서버정보입니다.
## 인증서 확인
kubectl get secret webapp-credential -n istio-system -o yaml | \
grep tls.crt | awk '{print $2}' | base64 -d | \
openssl x509 -text -noout | grep Issuer -A 4
Issuer: C=US, ST=Denial, O=Dis, CN=webapp.istioinaction.io
Validity
Not Before: Jul 4 12:49:32 2021 GMT
Not After : Jun 29 12:49:32 2041 GMT
Subject: C=US, ST=Denial, L=Springfield, O=Dis, CN=webapp.istioinaction.io
..
서버 인증서(Secret) 적용 (Gateway)
# vi ch4/coolstore-gw-tls.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: coolstore-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "webapp.istioinaction.io"
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: SIMPLE
credentialName: webapp-credential
hosts:
- "webapp.istioinaction.io"
kubectl apply -f ch4/coolstore-gw-tls.yaml -n istioinaction
호출테스트 1
curl -v -H "Host: webapp.istioinaction.io" https://127.0.0.1/api/catalog
* Trying 127.0.0.1:443...
* Connected to localhost (127.0.0.1) port 443 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
* CAfile: /etc/ssl/cert.pem
* CApath: none
* (304) (OUT), TLS handshake, Client hello (1):
* LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 127.0.0.1:443
* Closing connection 0
curl: (35) LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 127.0.0.1:443
⇒ (호출 실패) 원인: (기본 인증서 경로에) 인증서 없음. 사설인증서 이므로 “사설CA 인증서(체인)” 필요
호출테스트 2 - “사설 CA인증서” 경로 추가
curl -v -H "Host: webapp.istioinaction.io" https://127.0.0.1:443/api/catalog \
--cacert ch4/certs/2_intermediate/certs/ca-chain.cert.pem
* Trying 127.0.0.1:443...
* Connected to 127.0.0.1 (127.0.0.1) port 443 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
* CAfile: ch4/certs/2_intermediate/certs/ca-chain.cert.pem
* CApath: none
* (304) (OUT), TLS handshake, Client hello (1):
* LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 127.0.0.1:443
* Closing connection 0
curl: (35) LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 127.0.0.1:443
⇒ (호출 실패) 원인: 인증실패. 서버인증서가 발급된(issued) 도메인 “webapp.istioinaction.io”로 호출하지 않음 (127.0.0.1로 호출함)
호출테스트 3 (성공)
“webapp.istioinaction.io” 도메인으로 호출 시 resolve를 127.0.0.1로 강제하도록 resolve 옵션 사용
curl -v https://webapp.istioinaction.io/api/catalog \
--cacert ch4/certs/2_intermediate/certs/ca-chain.cert.pem \
--resolve webapp.istioinaction.io:443:127.0.0.1
* Added webapp.istioinaction.io:443:127.0.0.1 to DNS cache
* Hostname webapp.istioinaction.io was found in DNS cache
* Trying 127.0.0.1:443...
* Connected to webapp.istioinaction.io (127.0.0.1) port 443 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
* CAfile: ch4/certs/2_intermediate/certs/ca-chain.cert.pem
* CApath: none
* (304) (OUT), TLS handshake, Client hello (1):
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256
* ALPN: server accepted h2
* Server certificate:
* subject: C=US; ST=Denial; L=Springfield; O=Dis; CN=webapp.istioinaction.io
* start date: Jul 4 12:49:32 2021 GMT
* expire date: Jun 29 12:49:32 2041 GMT
* common name: webapp.istioinaction.io (matched)
* issuer: C=US; ST=Denial; O=Dis; CN=webapp.istioinaction.io
* SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* h2h3 [:method: GET]
* h2h3 [:path: /api/catalog]
* h2h3 [:scheme: https]
* h2h3 [:authority: webapp.istioinaction.io]
* h2h3 [user-agent: curl/7.84.0]
* h2h3 [accept: */*]
* Using Stream ID: 1 (easy handle 0x14200bc00)
> GET /api/catalog HTTP/2
> Host: webapp.istioinaction.io
> user-agent: curl/7.84.0
> accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 2147483647)!
< HTTP/2 200
< content-length: 357
< content-type: application/json; charset=utf-8
< date: Sat, 24 Dec 2022 02:16:48 GMT
< x-envoy-upstream-service-time: 13
< server: istio-envoy
<
* Connection #0 to host webapp.istioinaction.io left intact
[{"id":1,"color":"amber","department":"Eyewear","name":"Elinor Glasses","price":"282.00"},{"id":2,"color":"cyan","department":"Clothing","name":"Atlas Shirt","price":"127.00"},{"id":3,"color":"teal","department":"Clothing","name":"Small Metal Shoes","price":"232.00"},{"id":4,"color":"red","department":"Watches","name":"Red Dragon Watch","price":"232.00"}]
HTTPS 강제하기
http 요청을 받더라도 https 로 강제 리다이렉트 설정 (우)
kubectl apply -f ch4/coolstore-gw-tls-redirect.yaml -n istioinaction
호출테스트 - http로 호출하더라도 https로 리다이렉트됨
curl -v -H "Host: webapp.istioinaction.io" http://127.0.0.1/api/catalog
* Trying 127.0.0.1:80...
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET /api/catalog HTTP/1.1
> Host: webapp.istioinaction.io
> User-Agent: curl/7.84.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 301 Moved Permanently
< location: https://webapp.istioinaction.io/api/catalog
< date: Sat, 24 Dec 2022 02:31:40 GMT
< server: istio-envoy
< content-length: 0
<
* Connection #0 to host localhost left intact
Mutual TLS
상호(mutual) 인증. 서버만 인증하는 것이 아니라 클라이언트도 인증을 받는다
Basic model of how mTLS is established between a client and sever (Istio IN ACTION, p.95)
Secret (클라이언트 인증서) 생성 (전체 복붙)
kubectl create -n istio-system secret \
generic webapp-credential-mtls --from-file=tls.key=\
ch4/certs/3_application/private/webapp.istioinaction.io.key.pem \
--from-file=tls.crt=\
ch4/certs/3_application/certs/webapp.istioinaction.io.cert.pem \
--from-file=ca.crt=\
ch4/certs/2_intermediate/certs/ca-chain.cert.pem
Gateway - Secret (클라이언트 인증서) 적용 (우)
kubectl apply -f ch4/coolstore-gw-mtls.yaml -n istioinaction
참고: ch4/coolstore-gw-mtls.yaml
호출테스트1
curl -v https://webapp.istioinaction.io/api/catalog \
--cacert ch4/certs/2_intermediate/certs/ca-chain.cert.pem \
--resolve webapp.istioinaction.io:443:127.0.0.1
* Added webapp.istioinaction.io:443:127.0.0.1 to DNS cache
* Hostname webapp.istioinaction.io was found in DNS cache
* Trying 127.0.0.1:443...
* Connected to webapp.istioinaction.io (127.0.0.1) port 443 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
* CAfile: ch4/certs/2_intermediate/certs/ca-chain.cert.pem
* CApath: none
* (304) (OUT), TLS handshake, Client hello (1):
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Request CERT (13):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Certificate (11):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256
* ALPN: server accepted h2
* Server certificate:
* subject: C=US; ST=Denial; L=Springfield; O=Dis; CN=webapp.istioinaction.io
* start date: Jul 4 12:49:32 2021 GMT
* expire date: Jun 29 12:49:32 2041 GMT
* common name: webapp.istioinaction.io (matched)
* issuer: C=US; ST=Denial; O=Dis; CN=webapp.istioinaction.io
* SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* h2h3 [:method: GET]
* h2h3 [:path: /api/catalog]
* h2h3 [:scheme: https]
* h2h3 [:authority: webapp.istioinaction.io:443]
* h2h3 [user-agent: curl/7.84.0]
* h2h3 [accept: */*]
* Using Stream ID: 1 (easy handle 0x12980ec00)
> GET /api/catalog HTTP/2
> Host: webapp.istioinaction.io
> user-agent: curl/7.84.0
> accept: */*
>
* LibreSSL SSL_read: error:1404C45C:SSL routines:ST_OK:reason(1116), errno 0
* Failed receiving HTTP2 data
* LibreSSL SSL_write: SSL_ERROR_SYSCALL, errno 0
* Failed sending HTTP2 data
* Connection #0 to host webapp.istioinaction.io left intact
curl: (56) LibreSSL SSL_read: error:1404C45C:SSL routines:ST_OK:reason(1116), errno 0
⇒ (호출실패) 클라이언트 인증서 없음
호출테스트2 (성공) - 클라이언트 인증서/키 옵션추가
curl -v https://webapp.istioinaction.io/api/catalog \
--cacert ch4/certs/2_intermediate/certs/ca-chain.cert.pem \
--resolve webapp.istioinaction.io:443:127.0.0.1 \
--cert ch4/certs/4_client/certs/webapp.istioinaction.io.cert.pem \
--key ch4/certs/4_client/private/webapp.istioinaction.io.key.pem
* Added webapp.istioinaction.io:443:127.0.0.1 to DNS cache
* Hostname webapp.istioinaction.io was found in DNS cache
* Trying 127.0.0.1:443...
* Connected to webapp.istioinaction.io (127.0.0.1) port 443 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
* CAfile: ch4/certs/2_intermediate/certs/ca-chain.cert.pem
* CApath: none
* (304) (OUT), TLS handshake, Client hello (1):
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Request CERT (13):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Certificate (11):
* (304) (OUT), TLS handshake, CERT verify (15):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256
* ALPN: server accepted h2
* Server certificate:
* subject: C=US; ST=Denial; L=Springfield; O=Dis; CN=webapp.istioinaction.io
* start date: Jul 4 12:49:32 2021 GMT
* expire date: Jun 29 12:49:32 2041 GMT
* common name: webapp.istioinaction.io (matched)
* issuer: C=US; ST=Denial; O=Dis; CN=webapp.istioinaction.io
* SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* h2h3 [:method: GET]
* h2h3 [:path: /api/catalog]
* h2h3 [:scheme: https]
* h2h3 [:authority: webapp.istioinaction.io]
* h2h3 [user-agent: curl/7.84.0]
* h2h3 [accept: */*]
* Using Stream ID: 1 (easy handle 0x15400bc00)
> GET /api/catalog HTTP/2
> Host: webapp.istioinaction.io
> user-agent: curl/7.84.0
> accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 2147483647)!
< HTTP/2 200
< content-length: 357
< content-type: application/json; charset=utf-8
< date: Sat, 24 Dec 2022 02:51:48 GMT
< x-envoy-upstream-service-time: 6
< server: istio-envoy
<
* Connection #0 to host webapp.istioinaction.io left intact
[{"id":1,"color":"amber","department":"Eyewear","name":"Elinor Glasses","price":"282.00"},{"id":2,"color":"cyan","department":"Clothing","name":"Atlas Shirt","price":"127.00"},{"id":3,"color":"teal","department":"Clothing","name":"Small Metal Shoes","price":"232.00"},{"id":4,"color":"red","department":"Watches","name":"Red Dragon Watch","price":"232.00"}]
multi TLS
여러 Virtual host의 TLS 인증를 처리해 보자.
Secret 추가 - 서버인증서, catalog-credential
kubectl create -n istio-system secret tls catalog-credential \
--key ch4/certs2/3_application/private/catalog.istioinaction.io.key.pem \
--cert ch4/certs2/3_application/certs/catalog.istioinaction.io.cert.pem
(참고) 인증서(catalog-credential) 확인
kubectl get secret -n istio-system catalog-credential -o yaml | \
grep tls.crt | awk '{print $2}' | base64 -d | \
openssl x509 -text -noout | grep Issuer -A 4
Issuer: C=US, ST=Denial, O=Dis, CN=catalog.istioinaction.io
Validity
Not Before: Jul 4 13:30:38 2021 GMT
Not After : Jun 29 13:30:38 2041 GMT
Subject: C=US, ST=Denial, L=Springfield, O=Dis, CN=catalog.istioinaction.io
Gateway 수정 - Virtual host (catalog.istioinaction.io) 와 TLS (Secret, catalog-credential) 추가하기
kubectl apply -f ch4/coolstore-gw-multi-tls.yaml -n istioinaction
참고: ch4/coolstore-gw-multi-tls.yaml
VirtualService 추가 - catalog.istioinaction.io
# vi ch4/catalog-vs.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: catalog-vs-from-gw
spec:
hosts:
- "catalog.istioinaction.io"
gateways:
- coolstore-gateway
http:
- route:
- destination:
host: catalog
port:
number: 80
kubectl apply -f ch4/catalog-vs.yaml -n istioinaction
# kubectl get vs -n istioinaction
NAME GATEWAYS HOSTS AGE
catalog-vs-from-gw ["coolstore-gateway"] ["catalog.istioinaction.io"] 44s
webapp-vs-from-gw ["coolstore-gateway"] ["webapp.istioinaction.io"] 2d15h
호출테스트 1 - webapp.istioinaction.io
curl -v https://webapp.istioinaction.io/api/catalog \
--cacert ch4/certs/2_intermediate/certs/ca-chain.cert.pem \
--resolve webapp.istioinaction.io:443:127.0.0.1
호출테스트 2 - catalog.istioinaction.io (cacert 경로가 ch4/certs2/* 임에 유의)
curl -v https://catalog.istioinaction.io/items \
--cacert ch4/certs2/2_intermediate/certs/ca-chain.cert.pem \
--resolve catalog.istioinaction.io:443:127.0.0.1
* Added catalog.istioinaction.io:443:127.0.0.1 to DNS cache
* Hostname catalog.istioinaction.io was found in DNS cache
* Trying 127.0.0.1:443...
* Connected to catalog.istioinaction.io (127.0.0.1) port 443 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
* CAfile: ch4/certs2/2_intermediate/certs/ca-chain.cert.pem
* CApath: none
* (304) (OUT), TLS handshake, Client hello (1):
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256
* ALPN: server accepted h2
* Server certificate:
* subject: C=US; ST=Denial; L=Springfield; O=Dis; CN=catalog.istioinaction.io
* start date: Jul 4 13:30:38 2021 GMT
* expire date: Jun 29 13:30:38 2041 GMT
* common name: catalog.istioinaction.io (matched)
* issuer: C=US; ST=Denial; O=Dis; CN=catalog.istioinaction.io
* SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* h2h3 [:method: GET]
* h2h3 [:path: /items]
* h2h3 [:scheme: https]
* h2h3 [:authority: catalog.istioinaction.io]
* h2h3 [user-agent: curl/7.84.0]
* h2h3 [accept: */*]
* Using Stream ID: 1 (easy handle 0x15a00bc00)
> GET /items HTTP/2
> Host: catalog.istioinaction.io
> user-agent: curl/7.84.0
> accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 2147483647)!
< HTTP/2 200
< x-powered-by: Express
< vary: Origin, Accept-Encoding
< access-control-allow-credentials: true
< cache-control: no-cache
< pragma: no-cache
< expires: -1
< content-type: application/json; charset=utf-8
< content-length: 502
< etag: W/"1f6-ih2h+hDQ0yLLcKIlBvwkWbyQGK4"
< date: Sat, 24 Dec 2022 03:27:23 GMT
< x-envoy-upstream-service-time: 27
< server: istio-envoy
<
[
{
"id": 1,
"color": "amber",
"department": "Eyewear",
"name": "Elinor Glasses",
"price": "282.00"
},
{
"id": 2,
"color": "cyan",
"department": "Clothing",
"name": "Atlas Shirt",
"price": "127.00"
},
{
"id": 3,
"color": "teal",
"department": "Clothing",
"name": "Small Metal Shoes",
"price": "232.00"
},
{
"id": 4,
"color": "red",
"department": "Watches",
"name": "Red Dragon Watch",
"price": "232.00"
}
* Connection #0 to host catalog.istioinaction.io left intact
]