rewrite Secure Gateways (SDS) to use openssl for generating certs/keys (#6190)

* rewrite Secure Gateways (SDS) to use openssl for generating certs/keys

additional improvements:
1. Generate and use client certificate/private key for mutual TLS
2. Do not use quotes in YAMLs where not required

* add removing csr files and client.example.com files

* delete the directories with the certificates -> delete the certificates and the keys
This commit is contained in:
Vadim Eisenberg 2020-02-21 17:54:31 +02:00 committed by GitHub
parent 8f55ddbc67
commit 30f40a0e7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 67 additions and 102 deletions

View File

@ -42,44 +42,20 @@ extra steps required.
## Generate client and server certificates and keys ## Generate client and server certificates and keys
For this task you can use your favorite tool to generate certificates and keys. For this task you can use your favorite tool to generate certificates and keys. The commands below use
This example uses [a script](https://github.com/nicholasjackson/mtls-go-example/blob/master/generate.sh) [openssl](https://man.openbsd.org/openssl.1)
from the <https://github.com/nicholasjackson/mtls-go-example> repository.
1. Clone the [example's repository](https://github.com/nicholasjackson/mtls-go-example): 1. Create a root certificate and private key to sign the certificates for your services:
{{< text bash >}} {{< text bash >}}
$ git clone https://github.com/nicholasjackson/mtls-go-example $ openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example.com.key -out example.com.crt
{{< /text >}} {{< /text >}}
1. Go to the cloned repository: 1. Create a certificate and a private key for `httpbin.example.com`:
{{< text bash >}} {{< text bash >}}
$ pushd mtls-go-example $ openssl req -out httpbin.example.com.csr -newkey rsa:2048 -nodes -keyout httpbin.example.com.key -subj "/CN=httpbin.example.com/O=httpbin organization"
{{< /text >}} $ openssl x509 -req -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in httpbin.example.com.csr -out httpbin.example.com.crt
1. Generate the certificates for `httpbin.example.com`. Replace `<password>` with
any value in the following command:
{{< text bash >}}
$ ./generate.sh httpbin.example.com <password>
{{< /text >}}
When prompted, answer `y` to all the questions. The command generates
four directories: `1_root`, `2_intermediate`, `3_application`, and
`4_client` containing the client and server certificates to use in the
procedures below.
1. Move the certificates into a directory named `httpbin.example.com`:
{{< text bash >}}
$ mkdir ../httpbin.example.com && mv 1_root 2_intermediate 3_application 4_client ../httpbin.example.com
{{< /text >}}
1. Go back to your previous directory:
{{< text bash >}}
$ popd
{{< /text >}} {{< /text >}}
## Configure a TLS ingress gateway using SDS ## Configure a TLS ingress gateway using SDS
@ -169,9 +145,8 @@ need to create secrets for multiple hosts and update the gateway definitions.
1. Create a secret for the ingress gateway: 1. Create a secret for the ingress gateway:
{{< text bash >}} {{< text bash >}}
$ kubectl create -n istio-system secret generic httpbin-credential \ $ kubectl create -n istio-system secret generic httpbin-credential --from-file=key=httpbin.example.com.key \
--from-file=key=httpbin.example.com/3_application/private/httpbin.example.com.key.pem \ --from-file=cert=httpbin.example.com.crt
--from-file=cert=httpbin.example.com/3_application/certs/httpbin.example.com.cert.pem
{{< /text >}} {{< /text >}}
{{< warning >}} {{< warning >}}
@ -199,9 +174,9 @@ need to create secrets for multiple hosts and update the gateway definitions.
protocol: HTTPS protocol: HTTPS
tls: tls:
mode: SIMPLE mode: SIMPLE
credentialName: "httpbin-credential" # must be the same as secret credentialName: httpbin-credential # must be the same as secret
hosts: hosts:
- "httpbin.example.com" - httpbin.example.com
EOF EOF
{{< /text >}} {{< /text >}}
@ -236,10 +211,8 @@ need to create secrets for multiple hosts and update the gateway definitions.
1. Send an HTTPS request to access the `httpbin` service through HTTPS: 1. Send an HTTPS request to access the `httpbin` service through HTTPS:
{{< text bash >}} {{< text bash >}}
$ curl -v -HHost:httpbin.example.com \ $ curl -v -HHost:httpbin.example.com --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \
--resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \ --cacert example.com.crt https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418
--cacert httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem \
https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418
{{< /text >}} {{< /text >}}
The `httpbin` service will return the The `httpbin` service will return the
@ -253,22 +226,20 @@ need to create secrets for multiple hosts and update the gateway definitions.
{{< /text >}} {{< /text >}}
{{< text bash >}} {{< text bash >}}
$ pushd mtls-go-example $ mkdir new_certificates
$ ./generate.sh httpbin.example.com <password> $ openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout new_certificates/example.com.key -out new_certificates/example.com.crt
$ mkdir ../httpbin.new.example.com && mv 1_root 2_intermediate 3_application 4_client ../httpbin.new.example.com $ openssl req -out new_certificates/httpbin.example.com.csr -newkey rsa:2048 -nodes -keyout new_certificates/httpbin.example.com.key -subj "/CN=httpbin.example.com/O=httpbin organization"
$ popd $ openssl x509 -req -days 365 -CA new_certificates/example.com.crt -CAkey new_certificates/example.com.key -set_serial 0 -in new_certificates/httpbin.example.com.csr -out new_certificates/httpbin.example.com.crt
$ kubectl create -n istio-system secret generic httpbin-credential \ $ kubectl create -n istio-system secret generic httpbin-credential \
--from-file=key=httpbin.new.example.com/3_application/private/httpbin.example.com.key.pem \ --from-file=key=new_certificates/httpbin.example.com.key \
--from-file=cert=httpbin.new.example.com/3_application/certs/httpbin.example.com.cert.pem --from-file=cert=new_certificates/httpbin.example.com.crt
{{< /text >}} {{< /text >}}
1. Access the `httpbin` service using `curl` 1. Access the `httpbin` service using `curl` using the new certificate chain:
{{< text bash >}} {{< text bash >}}
$ curl -v -HHost:httpbin.example.com \ $ curl -v -HHost:httpbin.example.com --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \
--resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \ --cacert new_certificates/example.com.crt https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418
--cacert httpbin.new.example.com/2_intermediate/certs/ca-chain.cert.pem \
https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418
... ...
HTTP/2 418 HTTP/2 418
... ...
@ -286,16 +257,14 @@ need to create secrets for multiple hosts and update the gateway definitions.
1. If you try to access `httpbin` with the previous certificate chain, the attempt now fails. 1. If you try to access `httpbin` with the previous certificate chain, the attempt now fails.
{{< text bash >}} {{< text bash >}}
$ curl -v -HHost:httpbin.example.com \ $ curl -v -HHost:httpbin.example.com --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \
--resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \ --cacert example.com.crt https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418
--cacert httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem \
https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418
... ...
* TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS alert, Server hello (2): * TLSv1.2 (OUT), TLS alert, Server hello (2):
* SSL certificate problem: unable to get local issuer certificate * curl: (35) error:04FFF06A:rsa routines:CRYPTO_internal:block type is not 01
{{< /text >}} {{< /text >}}
### Configure a TLS ingress gateway for multiple hosts ### Configure a TLS ingress gateway for multiple hosts
@ -309,8 +278,8 @@ retrieves unique credentials corresponding to a specific `credentialName`.
{{< text bash >}} {{< text bash >}}
$ kubectl -n istio-system delete secret httpbin-credential $ kubectl -n istio-system delete secret httpbin-credential
$ kubectl create -n istio-system secret generic httpbin-credential \ $ kubectl create -n istio-system secret generic httpbin-credential \
--from-file=key=httpbin.example.com/3_application/private/httpbin.example.com.key.pem \ --from-file=key=httpbin.example.com.key \
--from-file=cert=httpbin.example.com/3_application/certs/httpbin.example.com.cert.pem --from-file=cert=httpbin.example.com.crt
{{< /text >}} {{< /text >}}
1. Start the `helloworld-v1` sample 1. Start the `helloworld-v1` sample
@ -358,17 +327,18 @@ retrieves unique credentials corresponding to a specific `credentialName`.
EOF EOF
{{< /text >}} {{< /text >}}
1. Create a secret for the ingress gateway. If you created the `httpbin-credential` 1. Generate a certificate and a private key for `helloworld-v1.example.com`:
secret already, you can now create the `helloworld-credential` secret.
{{< text bash >}} {{< text bash >}}
$ pushd mtls-go-example $ openssl req -out helloworld-v1.example.com.csr -newkey rsa:2048 -nodes -keyout helloworld-v1.example.com.key -subj "/CN=helloworld-v1.example.com/O=helloworld organization"
$ ./generate.sh helloworld-v1.example.com <password> $ openssl x509 -req -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 1 -in helloworld-v1.example.com.csr -out helloworld-v1.example.com.crt
$ mkdir ../helloworld-v1.example.com && mv 1_root 2_intermediate 3_application 4_client ../helloworld-v1.example.com {{< /text >}}
$ popd
$ kubectl create -n istio-system secret generic helloworld-credential \ 1. Create the `helloworld-credential` secret:
--from-file=key=helloworld-v1.example.com/3_application/private/helloworld-v1.example.com.key.pem \
--from-file=cert=helloworld-v1.example.com/3_application/certs/helloworld-v1.example.com.cert.pem {{< text bash >}}
$ kubectl create -n istio-system secret generic helloworld-credential --from-file=key=helloworld-v1.example.com.key \
--from-file=cert=helloworld-v1.example.com.crt
{{< /text >}} {{< /text >}}
1. Define a gateway with two server sections for port 443. Set the value of 1. Define a gateway with two server sections for port 443. Set the value of
@ -391,18 +361,18 @@ retrieves unique credentials corresponding to a specific `credentialName`.
protocol: HTTPS protocol: HTTPS
tls: tls:
mode: SIMPLE mode: SIMPLE
credentialName: "httpbin-credential" credentialName: httpbin-credential
hosts: hosts:
- "httpbin.example.com" - httpbin.example.com
- port: - port:
number: 443 number: 443
name: https-helloworld name: https-helloworld
protocol: HTTPS protocol: HTTPS
tls: tls:
mode: SIMPLE mode: SIMPLE
credentialName: "helloworld-credential" credentialName: helloworld-credential
hosts: hosts:
- "helloworld-v1.example.com" - helloworld-v1.example.com
EOF EOF
{{< /text >}} {{< /text >}}
@ -417,7 +387,7 @@ retrieves unique credentials corresponding to a specific `credentialName`.
name: helloworld-v1 name: helloworld-v1
spec: spec:
hosts: hosts:
- "helloworld-v1.example.com" - helloworld-v1.example.com
gateways: gateways:
- mygateway - mygateway
http: http:
@ -435,20 +405,16 @@ retrieves unique credentials corresponding to a specific `credentialName`.
1. Send an HTTPS request to `helloworld-v1.example.com`: 1. Send an HTTPS request to `helloworld-v1.example.com`:
{{< text bash >}} {{< text bash >}}
$ curl -v -HHost:helloworld-v1.example.com \ $ curl -v -HHost:helloworld-v1.example.com --resolve helloworld-v1.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \
--resolve helloworld-v1.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \ --cacert example.com.crt https://helloworld-v1.example.com:$SECURE_INGRESS_PORT/hello
--cacert helloworld-v1.example.com/2_intermediate/certs/ca-chain.cert.pem \
https://helloworld-v1.example.com:$SECURE_INGRESS_PORT/hello
HTTP/2 200 HTTP/2 200
{{< /text >}} {{< /text >}}
1. Send an HTTPS request to `httpbin.example.com` and still get a teapot in return: 1. Send an HTTPS request to `httpbin.example.com` and still get a teapot in return:
{{< text bash >}} {{< text bash >}}
$ curl -v -HHost:httpbin.example.com \ $ curl -v -HHost:httpbin.example.com --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \
--resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \ --cacert example.com.crt https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418
--cacert httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem \
https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418
-=[ teapot ]=- -=[ teapot ]=-
_...._ _...._
@ -470,10 +436,8 @@ its clients, and we must use the name `cacert` to hold the CA certificate.
{{< text bash >}} {{< text bash >}}
$ kubectl -n istio-system delete secret httpbin-credential $ kubectl -n istio-system delete secret httpbin-credential
$ kubectl create -n istio-system secret generic httpbin-credential \ $ kubectl create -n istio-system secret generic httpbin-credential --from-file=key=httpbin.example.com.key \
--from-file=key=httpbin.example.com/3_application/private/httpbin.example.com.key.pem \ --from-file=cert=httpbin.example.com.crt --from-file=cacert=example.com.crt
--from-file=cert=httpbin.example.com/3_application/certs/httpbin.example.com.cert.pem \
--from-file=cacert=httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem
{{< /text >}} {{< /text >}}
1. Change the gateway's definition to set the TLS mode to `MUTUAL`. 1. Change the gateway's definition to set the TLS mode to `MUTUAL`.
@ -494,19 +458,17 @@ $ kubectl create -n istio-system secret generic httpbin-credential \
protocol: HTTPS protocol: HTTPS
tls: tls:
mode: MUTUAL mode: MUTUAL
credentialName: "httpbin-credential" # must be the same as secret credentialName: httpbin-credential # must be the same as secret
hosts: hosts:
- "httpbin.example.com" - httpbin.example.com
EOF EOF
{{< /text >}} {{< /text >}}
1. Attempt to send an HTTPS request using the prior approach and see how it fails: 1. Attempt to send an HTTPS request using the prior approach and see how it fails:
{{< text bash >}} {{< text bash >}}
$ curl -v -HHost:httpbin.example.com \ $ curl -v -HHost:httpbin.example.com --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \
--resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \ --cacert example.com.crt https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418
--cacert httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem \
https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418
* TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
@ -521,16 +483,20 @@ $ kubectl create -n istio-system secret generic httpbin-credential \
* OpenSSL SSL_read: error:1409445C:SSL routines:ssl3_read_bytes:tlsv13 alert certificate required, errno 0 * OpenSSL SSL_read: error:1409445C:SSL routines:ssl3_read_bytes:tlsv13 alert certificate required, errno 0
{{< /text >}} {{< /text >}}
1. Generate client certificate and private key:
{{< text bash >}}
$ openssl req -out client.example.com.csr -newkey rsa:2048 -nodes -keyout client.example.com.key -subj "/CN=client.example.com/O=client organization"
$ openssl x509 -req -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 1 -in client.example.com.csr -out client.example.com.crt
{{< /text >}}
1. Pass a client certificate and private key to `curl` and resend the request. 1. Pass a client certificate and private key to `curl` and resend the request.
Pass your client's certificate with the `--cert` flag and your private key Pass your client's certificate with the `--cert` flag and your private key
with the `--key` flag to `curl`. with the `--key` flag to `curl`.
{{< text bash >}} {{< text bash >}}
$ curl -v -HHost:httpbin.example.com \ $ curl -v -HHost:httpbin.example.com --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \
--resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \ --cacert example.com.crt --cert client.example.com.crt --key client.example.com.key \
--cacert httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem \
--cert httpbin.example.com/4_client/certs/httpbin.example.com.cert.pem \
--key httpbin.example.com/4_client/private/httpbin.example.com.key.pem \
https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418 https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418
-=[ teapot ]=- -=[ teapot ]=-
@ -555,10 +521,9 @@ $ kubectl create -n istio-system secret generic httpbin-credential \
{{< text bash >}} {{< text bash >}}
$ kubectl -n istio-system delete secret httpbin-credential $ kubectl -n istio-system delete secret httpbin-credential
$ kubectl create -n istio-system secret generic httpbin-credential \ $ kubectl create -n istio-system secret generic httpbin-credential \
--from-file=key=httpbin.example.com/3_application/private/httpbin.example.com.key.pem \ --from-file=key=httpbin.example.com.key --from-file=cert=httpbin.example.com.crt
--from-file=cert=httpbin.example.com/3_application/certs/httpbin.example.com.cert.pem
$ kubectl create -n istio-system secret generic httpbin-credential-cacert \ $ kubectl create -n istio-system secret generic httpbin-credential-cacert \
--from-file=cacert=httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem --from-file=cacert=example.com.crt
{{< /text >}} {{< /text >}}
## Troubleshooting ## Troubleshooting
@ -621,10 +586,10 @@ $ kubectl create -n istio-system secret generic httpbin-credential \
$ kubectl delete --ignore-not-found=true virtualservice helloworld-v1 $ kubectl delete --ignore-not-found=true virtualservice helloworld-v1
{{< /text >}} {{< /text >}}
1. Delete the directories of the certificates and the repository used to generate them: 1. Delete the certificates and keys:
{{< text bash >}} {{< text bash >}}
$ rm -rf httpbin.example.com helloworld-v1.example.com mtls-go-example $ rm -rf example.com.crt example.com.key httpbin.example.com.crt httpbin.example.com.key httpbin.example.com.csr helloworld-v1.example.com.crt helloworld-v1.example.com.key helloworld-v1.example.com.csr client.example.com.crt client.example.com.csr client.example.com.key ./new_certificates
{{< /text >}} {{< /text >}}
1. Remove the file you used for redeployment of the ingress gateway. 1. Remove the file you used for redeployment of the ingress gateway.
@ -636,6 +601,6 @@ $ kubectl create -n istio-system secret generic httpbin-credential \
1. Shutdown the `httpbin` and `helloworld-v1` services: 1. Shutdown the `httpbin` and `helloworld-v1` services:
{{< text bash >}} {{< text bash >}}
$ kubectl delete service --ignore-not-found=true helloworld-v1 $ kubectl delete deployment --ignore-not-found=true httpbin helloworld-v1
$ kubectl delete service --ignore-not-found=true httpbin $ kubectl delete service --ignore-not-found=true httpbin helloworld-v1
{{< /text >}} {{< /text >}}