Open c0c0n3 opened 2 years ago
So I've tested the TLS setup a bit and we could start from this Istio gateway config which builds on the existing gateway definition to add a TLS endpoint, handle TLS termination and redirect plain HTTP traffic to the TLS endpoint.
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: "kitt4sme-gateway"
spec:
selector:
istio: ingressgateway
servers:
- hosts:
- "*"
port:
name: http
number: 80
protocol: HTTP
tls:
httpsRedirect: true
- hosts:
- "*"
port:
number: 443
name: https
protocol: HTTPS
tls:
mode: SIMPLE
credentialName: istio-gw-cert
Notice the credentialName: istio-gw-cert
up there. That's where we've got to plonk down a valid certificate. Once we've got one, in principle we should just be able to create a K8s secret for it like this
$ kubectl create -n istio-system secret tls istio-gw-cert \
--key=istio-gw.key-pair.pem --cert=istio-gw.crt.pem
Notice we can't automate this step since the certificate and its private/pub key should be kept secret---so obviously we must not stash that away in source control.
See also:
I did some tests to address this issue, find then below. You can find the yaml files in the next repo: k8s-kc-tests
Note: This part will not be required once we have the official certificates
Create root certificate
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout root-example.com.key -out root-example.com.crt
Create certificate and key for Keycloak (kc.example.com)
openssl req -out kc.example.com.csr -newkey rsa:2048 -nodes -keyout kc.example.com.key -subj "/CN=kc.example.com/O=Keycloak Org"
openssl x509 -req -days 365 -CA root-example.com.crt -CAkey root-example.com.key -set_serial 0 -in kc.example.com.csr -out kc.example.com.crt
Get certificate info
openssl x509 -text -noout -in root-example.com.crt
openssl x509 -text -noout -in kc.example.com.crt
Create the certs dirs for being used as volume
mkdir certs
cp kc.example.com.crt certs/tls.crt
cp kc.example.com.key certs/tls.key
Launch docker image (mapping the certs dir as a volume)
sudo docker run --name keycloak -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin -p 8443:8443 -v $(pwd)/certs:/etc/x509/https jboss/keycloak
Get certificate info
openssl s_client -showcerts -connect localhost:8443
sudo docker rm keycloak
sudo docker volume prune
Create specific namespace for Keycloak (optional)
kubectl create ns kc
Apply the yaml
kubectl -n kc apply -f keycloak-simple.yaml
Note: check your volumes > hostPath . It can be different in your setup
Forward port
kubectl -n kc port-forward svc/keycloak 8443:8443 --address 0.0.0.0
Get and check certificate info
openssl s_client -showcerts -connect localhost:8443
Clean Everything
kubectl delete ns kc
Create specific namespace for Keycloak
kubectl create ns kc
Enable Istio injection
kubectl label namespace kc istio-injection=enabled
Apply the Keycloak yaml
kubectl -n kc apply -f keycloak-simple.yaml
Apply the gateway
kubectl -n kc apply -f kc-gw.yaml
Apply the virtual service for routing
kubectl -n kc apply -f kc-routing.yaml
Test the GW and the routing
curl -v localhost:80
Optional Add a Authorization Policy to block the access to some reources. (e.g jboss_community.png)
kubectl apply -f kc-img-block-policy.yaml
Optional Check the access to jboss_community.png is forbidden
curl -v http://localhost/auth/welcome-content/jboss_community.png -o /dev/null
Clean Everything
kubectl delete ns kc
kubectl -n istio-system delete authorizationpolicy ingress-img-block-policy
Create specific namespace for Keycloak
kubectl create ns kc
Enable Istio injection
kubectl label namespace kc istio-injection=enabled
Apply the Keycloak yaml
kubectl -n kc apply -f keycloak-simple.yaml
Note: due to the TLS termination the certificate in KC is not needed, you can replace the line above with keycloak without Certs
kubectl -n kc apply -f keycloak-nocert.yaml
Create the secret for the Ingress Gateway
kubectl create -n istio-system secret tls kc-tls --key=certs/tls.key --cert=certs/tls.crt
Apply the gateway
kubectl -n kc apply -f kc-sec-gw.yaml
Apply the virtual service for routing
kubectl -n kc apply -f kc-routing.yaml
Test the GW and the routing (with and without TLS/SSL)
curl -L -v http://localhost
curl -L -v https://localhost
openssl s_client -showcerts -connect localhost:443
Clean Everything
kubectl delete ns kc
kubectl -n istio-system delete secret kc-tls
The last option With Ingress and TLS/SSL was tested with Keycloak requiring HTTPS for: 'None', 'External requests' and 'All requests'
To apply and test this above in the K4S mesh, we could update the Gateway to something similar to what @c0c0n3 described in (https://github.com/c0c0n3/kitt4sme.live/issues/77#issuecomment-1019264450), e.g:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: kitt4sme-gateway
namespace: default
spec:
selector:
istio: ingressgateway
servers:
- hosts:
- "*"
port:
number: 80
name: http
protocol: HTTP
tls:
httpsRedirect: false # set to true if you want to force the redirection to HTTPS
- hosts:
- "*"
port:
number: 443
name: https
protocol: HTTPS
tls:
mode: SIMPLE
credentialName: kc-tls
and test it with:
curl --insecure -L -v https://localhost/auth
or
openssl s_client -showcerts -connect localhost:443
@karikolehmainen please wire in the TLS certificate you have so we can close this issue. Thanks!
Summary
Make all HTTP traffic between the platform and external processes go through TLS channels.
Intended outcome
HTTP communication between external parties and platform services is private and the exchanged data can't be tampered with.
How will it work?
External processes can only do HTTP calls to platform services through a secure TLS channel. The Istio ingress gateway accepts external HTTPS traffic on port 443 and redirects plain HTTP (port 80 at the moment) to port 443. Also, the gateway gets configured with a valid certificate for kitt4sme.collab-cloud.eu so it can do TLS termination.