Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new module for ingress/egress #68

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions apps/product_catalog/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0
# Use an official Python runtime as an image
FROM python:3.9-slim
#FROM python:3.9-slim
FROM public.ecr.aws/amazonlinux/amazonlinux:latest

RUN apt-get update \
&& apt-get install curl -y \
&& rm -rf /var/lib/apt/lists/*
#RUN apt-get update \
# && apt-get install curl -y \
# && rm -rf /var/lib/apt/lists/*

RUN dnf -y localinstall https://dev.mysql.com/get/mysql80-community-release-el9-4.noarch.rpm && \
dnf -y install mysql mysql-community-client && \
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && \
yum install -y unzip && \
unzip awscliv2.zip && \
./aws/install && \
yum install -y pip

RUN mkdir /app
WORKDIR /app
Expand Down
13 changes: 7 additions & 6 deletions apps/product_catalog/app_aurora.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
DB_USER_NAME = os.environ.get("DATABASE_USER_NAME")
#DB_TOKEN = os.environ.get("DATABASE_TOKEN")
DB_NAME = os.environ.get("DB_NAME")
DB_PORT = os.environ.get("DB_PORT")
DB_PORT = int(os.environ.get("DB_PORT"))
DB_REGION = os.environ.get("DB_REGION")

list_of_names = ""
Expand All @@ -45,7 +45,8 @@

os.environ['LIBMYSQL_ENABLE_CLEARTEXT_PLUGIN'] = '1'

SSL_CA='rds-combined-ca-bundle.pem'
#SSL_CA='rds-combined-ca-bundle.pem'
SSL_CA='global-bundle.pem'

flask_app.logger.info(SSL_CA)

Expand All @@ -55,13 +56,13 @@
# Connect to the database
def create_connection():
# Construct SSL
ssl = {'ca': 'rds-combined-ca-bundle.pem'}
ssl = {'ca': SSL_CA}
token = client.generate_db_auth_token(DBHostname=DB_APP_URL, Port=3306, DBUsername=DB_USER_NAME, Region=DB_REGION)
flask_app.logger.info('token ' + token)
flask_app.logger.info('token ' + token + ' DB ' + DB_NAME + ' Port ' + str(DB_PORT))
return pymysql.connect(host=DB_APP_URL,
user=DB_USER_NAME,
password=token,
port=3306,
port=DB_PORT,
db=DB_NAME,
ssl=ssl,
charset='utf8mb4',
Expand Down Expand Up @@ -213,4 +214,4 @@ def post(self, id):


if __name__ == '__main__':
app.run(host="0.0.0.0", debug=True)
app.run(host="0.0.0.0", debug=True)
2 changes: 1 addition & 1 deletion apps/product_catalog/bootstrap.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
export FLASK_APP=./app.py
export FLASK_APP=./app_aurora.py
export FLASK_DEBUG=1
flask run -h 0.0.0.0
3,028 changes: 3,028 additions & 0 deletions apps/product_catalog/global-bundle.pem

Large diffs are not rendered by default.

179 changes: 179 additions & 0 deletions modules/04-securing-ingress-egress/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
# Module 3 - Securing Inngress and Egress traffic

This module shows the ingress and egress traffic to the mesh can be controlled and secured. The module is split into two sub modules one for ingress and other for egress.

1. [Secure Ingress](#control-ingress)
2. [Secure Egress](#control-egress)

## Prerequisites:
- [Module 1 - Getting Started](../01-getting-started/)

## Securing ingress traffic

One of the key components of Istio is its ingress gateway, which serves as the entry point for incoming traffic into the service mesh. (TBD - add more details on ingress gateway and their importance before this sentence)

When it comes to securing the transport layer using Transport Layer Security (TLS) with Istio Ingress, there are two main approaches:

1. TLS Termination at Ingress Gateway: In this approach traffic is encrypted using TLS till ingress gateway. Ingress gateway can terminate TLS connections from external client and forward the traffic the traffic to component services within the mesh.

2. Istio supports mutual TLS authentication, which ensures that both the client and the server authenticate each other using certificates. With mTLS enabled, communication between services within the mesh is encrypted and authenticated, providing an additional layer of security.


### Securing ingress traffic with TLS

To secure ingress traffic using TLS, we need to generate certficates and share the certificates keys with Ingress gateway through a K8s secret. Ingress gateway will use the shared certificate keys to establish TLS session with the client and allow for secure communication between the client and the services behind the ingress gateway in the mesh. A key consideration is that the TLS connection will be terminated at the Ingress gateway and further encryption of the traffic will depend on the traffic encryption policy within the mesh.

For this blog, we will use self signed certificates but for your production workloads it is recommend to use certificates from trusted CAs like AWS Certificate Manager.

1. Let us create the self signed certificates and import them to AWS Certificate Manager (ACM). To do this, we have use the terraform template defined below and apply it to create the certificate resources

```sh
cd secure-ingress-tls
terraform init
terraform plan
terraform apply -auto-approve
```

2. Now you should be able to see certificate and key generated in the 'certs' directory and certificate material imported to ACM.
```sh
ls certs
istio-tls-root-cert.cert istio-tls-root-private-key.key
```
```sh
export CERT_ARN=$(terraform output | cut -d '=' -f 2 | tr -d '"' | tr -d ' ')
aws acm describe-certificate --certificate-arn $CERT_ARN
```

3. The next step is to create an ingress gateway that will allow only TLS traffic from external sources through a network load balancer to the gateway.

To support this configuration, we have to customize the ingress gateway pods to expose only ports 443 and 15020, configure the NLB to expose only the 443 port to external clients, and configure the 15020 port for performing health checks on the ingress gateway pods. We then need to configure the NLB and the ingress gateway pods to use the certificate we generated in the last step.

To configure the NLB with to use certificate we use the "service.beta.kubernetes.io/aws-load-balancer-ssl-cert" annotation as part of the ingress gateway service setup to refer the certificate.

For ingress pods, we will need to create Kubernetes TLS secret and provide it as part of the Istio Gateway object's TLS configuration.

```sh
kubectl create -n istio-ingress secret tls istio-tls-credential --key=certs/istio-tls-root-private-key.key --cert=certs/istio-tls-root-cert.cert
cd helm
helm install --set certARN=$CERT_ARN istio-tls-ingress-nlb .
```

Test the ingress routing

```sh
export URL=$(k describe svc istio-ingressgateway-tls -n istio-ingress | grep -i 'LoadBalancer Ingress:' | cut -d ':' -f 2 | tr -d ' ')
curl -o /dev/null -I -w "%{http_code}" https://${URL}/ --cacert ../certs/istio-tls-root-cert.cert
```

clean up
```sh
helm uninstall istio-tls-ingress-nlb
cd ..
terraform destroy --auto-approve
cd ..
kubectl delete secret istio-tls-credential -n istio-ingress
```

### Securing ingress traffic with mTLS

configure mtls

a. create certificate bundle from the client certificates
b. configure the certificate bundle to the ingress gateway for the clients

```sh
cd controll-ingress-mTLS-auth
terraform init
terraform plan
terraform apply -auto-approve
```

```sh
kubectl create -n istio-ingress secret generic istio-mtls-credential --from-file=tls.key=certs/istio-mtls-root-private-key.key --from-file=tls.crt=certs/istio-mtls-root-cert.cert --from-file=ca.crt=certs/client-1-mtls-root-cert.cert
cd helm
helm install istio-mtls-ingress-nlb .
```

Test the ingress routing

```sh
export URL=$(kubectl get svc istio-ingressgateway-mtls -n istio-ingress -o json | jq -r '.status.loadBalancer.ingress[].hostname')
curl -o /dev/null -I -w "%{http_code}" https://${URL}/ --cacert ../certs/istio-mtls-root-cert.cert --key ../certs/client-1-mtls-root-private-key.key --cert ../certs/client-1-mtls-root-cert.cert

curl -o /dev/null -I -w "%{http_code}" https://${URL}/ --cacert ../certs/istio-mtls-root-cert.cert --key ../certs/client-2-mtls-root-private-key.key --cert ../certs/client-2-mtls-root-cert.cert
```

clean up
```sh
helm uninstall istio-mtls-ingress-nlb
cd ..
terraform destroy --auto-approve
kubectl delete secret istio-mtls-credential -n istio-ingress
cd ..
```
### Controlling ingress traffic with mTLS authorization

### Using application load balancer to offload mTLS validation to the load balancer

configure mtls with alb in proxy mode

a. create trust bundle from the client certificates
b. configure the trus bundle to the ingress gateway for the clients

```sh
cd offload-mTLS-auth-ALB
terraform init
terraform plan
terraform apply -auto-approve
```

```sh
aws s3 mb s3://mahali-istio-alb-truststore
#aws s3api put-bucket-versioning --bucket mahali-istio-alb-truststore --versioning-configuration Status=Enabled
aws s3 cp certs/client-1-mtls-ca-cert.cert s3://mahali-istio-alb-truststore/trust-store/client-1-mtls-ca-cert.cert
export trustStoreARN=$(aws elbv2 create-trust-store --name istio-alb-truststore --ca-certificates-bundle-s3-bucket mahali-istio-alb-truststore --ca-certificates-bundle-s3-key trust-store/client-1-mtls-ca-cert.cert | jq -r '.TrustStores[].TrustStoreArn')
```

```sh
export CERT_ARN=$(terraform output | cut -d '=' -f 2 | tr -d '"' | tr -d ' ')
aws acm describe-certificate --certificate-arn $CERT_ARN
kubectl create -n istio-ingress secret tls istio-tls-credential --key=certs/istio-mtls-root-private-key.key --cert=certs/istio-mtls-root-cert.cert
```

```sh
cd helm
helm install --set certARN=$CERT_ARN --set trustStoreARN=$trustStoreARN istio-mtls-ingress-alb .
```

Test the ingress routing

```sh
export URL=$(kubectl get ingress istio-ingress-tls -n istio-ingress -o json | jq -r '.status.loadBalancer.ingress[].hostname')
curl -o /dev/null -I -w "%{http_code}" https://${URL}/ --cacert ../certs/istio-mtls-root-cert.cert --key ../certs/client-1-mtls-private-key.key --cert ../certs/client-1-mtls-cert.cert

```

clean up
```sh
helm uninstall istio-mtls-ingress-alb
cd ..
terraform destroy --auto-approve
kubectl delete secret istio-tls-credential -n istio-ingress
aws elbv2 delete-trust-store --trust-store-arn $trustStoreARN
aws s3 rm s3://mahali-istio-alb-truststore/trust-store/client-1-mtls-ca-cert.cert
aws s3 rb s3://mahali-istio-alb-truststore
cd ..
```

### Securing egress traffic

#### Securing calls to service exposed through HTTPS endpoint.

In this pattern the call from the Pod to Envoy proxy would be through HTTP and Envoy proxy would initiate the HTTPS call to the service on behalf
of the Pod. The call between the Pod and Egress is secured with mTLS. In this approach, policies can be applied on the Egress gateway to control

```sh
cd cd 04-securing-ingress-egress/secure-egress-https/tls-origination/
```

b. mTLS and TLS orgination at egress gateway
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
apiVersion: v1
appVersion: "1.0"
description: Helm Chart for Istio ingress with TLS enabled
name: istio-mtls-ingress-nlb
version: 1.0.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
apiVersion: v1
kind: Service
metadata:
name: istio-ingressgateway-mtls
namespace: istio-ingress
annotations:
service.beta.kubernetes.io/aws-load-balancer-name: istio-ingress-mtls
service.beta.kubernetes.io/aws-load-balancer-healthcheck-protocol: HTTP
service.beta.kubernetes.io/aws-load-balancer-healthcheck-port: "15021"
service.beta.kubernetes.io/aws-load-balancer-type: external
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
service.beta.kubernetes.io/aws-load-balancer-healthcheck-path: /healthz/ready
#service.beta.kubernetes.io/aws-load-balancer-ssl-cert: {{.Values.certARN}}
service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
spec:
selector:
istio: ingressgateway-mtls
ports:
- port: 443
name: https
#- port: 15443
# name: hltchkport
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: istio-ingressgateway-mtls
namespace: istio-ingress
spec:
selector:
matchLabels:
istio: ingressgateway-mtls
template:
metadata:
annotations:
# Select the gateway injection template (rather than the default sidecar template)
inject.istio.io/templates: gateway
labels:
# Set a unique label for the gateway. This is required to ensure Gateways can select this workload
istio: ingressgateway-mtls
# Enable gateway injection. If connecting to a revisioned control plane, replace with "istio.io/rev: revision-name"
sidecar.istio.io/inject: "true"
spec:
# Allow binding to all ports (such as 80 and 443)
securityContext:
sysctls:
- name: net.ipv4.ip_unprivileged_port_start
value: "0"
containers:
- name: istio-proxy
image: auto # The image will automatically update each time the pod starts.
# Drop all privileges, allowing to run as non-root
securityContext:
capabilities:
drop:
- ALL
runAsUser: 1337
runAsGroup: 1337
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: productapp-gateway-mtls
namespace: workshop
spec:
# The selector matches the ingress gateway pod labels.
# If you installed Istio using Helm following the standard documentation, this would be "istio=ingress"
selector:
istio: ingressgateway-mtls # use istio default controller
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: MUTUAL
credentialName: istio-mtls-credential # must be the same as secret
hosts:
- "*"
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: productapp-mtls
namespace: workshop
spec:
hosts:
- "*"
gateways:
- productapp-gateway-mtls
http:
- match:
- uri:
prefix: /
route:
- destination:
host: frontend
port:
number: 9000
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: workshop-apps
namespace: workshop
spec:
mtls:
mode: STRICT
Loading