diff --git a/kind/bookinfo-istio/README.md b/kind/bookinfo-istio/README.md new file mode 100644 index 0000000..5fbf951 --- /dev/null +++ b/kind/bookinfo-istio/README.md @@ -0,0 +1,476 @@ +# Bookinfo with Istio and mTLS on KubeSlice - Deployment Guide + +This example deploys the Istio Bookinfo application across two KubeSlice-connected clusters with Istio service mesh and mTLS enabled for secure service-to-service communication. + +## Getting Started + +### Clone the Repository + +Begin by cloning the repository and navigating to the bookinfo-istio example directory: + +```bash +# Clone the repository +git clone https://github.com/kubeslice/examples.git + +# Navigate to the bookinfo-istio example directory +cd examples/kind/bookinfo-istio +``` + +### Cluster Information + +This guide uses the following Kubernetes clusters: + +- **Controller Cluster**: `gke_graphic-transit-458312-f7_us-central1_ks-controller` + - The KubeSlice controller that manages the slice configuration + +- **Product Cluster (Worker 1)**: `gke_graphic-transit-458312-f7_us-east1_ks-worker-1` + - Hosts the productpage service and Istio ingress gateway + +- **Services Cluster (Worker 2)**: `gke_graphic-transit-458312-f7_us-east1_ks-worker-2` + - Hosts the details, reviews, and ratings services + +> **Note**: You should replace these cluster contexts with your own when following this guide. The contexts mentioned are specific to the original setup. + +## Prerequisites + +- Two Kubernetes clusters connected via KubeSlice +- `kubectl` installed and configured to access both clusters +- `kubectx` for easier cluster switching (optional) +- `istioctl` for Istio installation and management +- Sufficient permissions to deploy resources in both clusters + +## Deployment Steps + +### 1. Create KubeSlice Configuration + +First, we need to create a slice configuration on the KubeSlice controller: + +```bash +# Switch to controller context +kubectx gke_graphic-transit-458312-f7_us-central1_ks-controller + +# Apply slice configuration +kubectl apply -f 'config_files/slice-config.yaml' +``` + +Expected output: +``` +sliceconfig.controller.kubeslice.io/bookinfo-slice created +``` + +### 2. Install Istio on Both Clusters + +Installing Istio using istioctl provides a simpler, more direct approach with built-in profiles. + +```bash +# Install Istio on Worker Cluster 1 (Product Cluster) +istioctl install --set profile=demo --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-1 -y + +# Install Istio on Worker Cluster 2 (Services Cluster) +istioctl install --set profile=demo --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-2 -y +``` + +Expected output for each command: +``` + |\ + | \ + | \ + | \ + /|| \ + / || \ + / || \ + / || \ + / || \ + / || \ +/______||__________\ +____________________ + \__ _____/ + \_____/ + +✔ Istio core installed ⛵️ +✔ Istiod installed 🧠 +✔ CNI installed 🪢 +✔ Egress gateways installed 🛫 +✔ Ingress gateways installed 🛬 +✔ Installation complete +``` + +> **Note**: If you see warnings about version downgrades or revision changes, these are generally safe to proceed with for a fresh installation. + +#### 2.1 Verify Istio Installation + +```bash +# Check Istio services +kubectl get svc -n istio-system +``` + +Expected output: +``` +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +istio-egressgateway ClusterIP 10.96.x.x 80/TCP,443/TCP 1m +istio-ingressgateway LoadBalancer 10.96.x.x 34.23.96.143 15021:31xxx/TCP,80:31xxx/TCP,443:31xxx/TCP 1m +istiod ClusterIP 10.96.x.x 15010/TCP,15012/TCP,443/TCP,15014/TCP 1m +``` + +Get the external IP of the ingress gateway: + +```bash +kubectl get svc istio-ingressgateway -n istio-system -o jsonpath='{.status.loadBalancer.ingress[0].ip}' +``` + +Expected output: +``` +34.23.96.143 +``` + +### 3. Prepare Application Namespace + +Perform these steps on both worker clusters: + +```bash +# Create bookinfo namespace +kubectl create namespace bookinfo + +# Enable Istio injection +kubectl label namespace bookinfo istio-injection=enabled +``` + +Expected output: +``` +namespace/bookinfo created +namespace/bookinfo labeled +``` + +> **Note**: If the namespace already exists, you'll see: "Error from server (AlreadyExists): namespaces "bookinfo" already exists" + +### 4. Deploy Bookinfo Application + +#### 4.1 Deploy Frontend on Worker Cluster 1 + +```bash +# Deploy productpage service +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-1 apply -f config_files/productpage.yaml -n bookinfo + +# Deploy Istio gateway for external access +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-1 apply -f config_files/gateway.yaml -n bookinfo +``` + +Expected output: +``` +service/productpage created +serviceaccount/bookinfo-productpage created +deployment.apps/productpage-v1 created +gateway.networking.istio.io/bookinfo-gateway created +virtualservice.networking.istio.io/bookinfo created +``` + +#### 4.2 Deploy Backend Services on Worker Cluster 2 + +```bash +# Deploy details service +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-2 apply -f config_files/details.yaml -n bookinfo + +# Deploy reviews service +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-2 apply -f config_files/reviews.yaml -n bookinfo + +# Deploy ratings service +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-2 apply -f config_files/ratings.yaml -n bookinfo +``` + +Expected output: +``` +service/details created +serviceaccount/bookinfo-details created +deployment.apps/details-v1 created +service/reviews created +serviceaccount/bookinfo-reviews created +deployment.apps/reviews-v3 created +service/ratings created +serviceaccount/bookinfo-ratings created +deployment.apps/ratings-v1 created +``` + +### 5. Configure KubeSlice ServiceExports + +Export services from Worker Cluster 2 to make them accessible in Worker Cluster 1: + +```bash +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-2 apply -f config_files/serviceexports.yaml -n bookinfo +``` + +Expected output: +``` +serviceexport.networking.kubeslice.io/details created +serviceexport.networking.kubeslice.io/reviews created +serviceexport.networking.kubeslice.io/ratings created +``` + +Verify ServiceExports on Worker Cluster 2: + +```bash +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-2 get serviceexports -n bookinfo +``` + +Initial output (status may be PENDING): +``` +NAME SLICE INGRESS SERVICEPORT(S) PORT(S) ENDPOINTS STATUS ALIAS +details convoy 9080/TCP PENDING +reviews convoy 9080/TCP PENDING +``` + +Wait a few minutes, then check again: + +```bash +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-2 get serviceexports -n bookinfo +``` + +Expected output after propagation: +``` +NAME SLICE INGRESS SERVICEPORT(S) PORT(S) ENDPOINTS STATUS ALIAS +details bookinfo-slice false 9080/TCP READY +ratings bookinfo-slice 9080/TCP READY +reviews bookinfo-slice false 9080/TCP READY +``` + +Verify ServiceImports on Worker Cluster 1: + +```bash +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-1 get serviceimports -n bookinfo +``` + +Expected output: +``` +NAME SLICE PORT(S) ENDPOINTS STATUS ALIAS +details bookinfo-slice 9080/TCP READY +ratings bookinfo-slice 9080/TCP READY +reviews bookinfo-slice 9080/TCP READY +``` + +### 6. Enable mTLS Security + +Apply strict mTLS policies to both clusters: + +```bash +# Apply strict mTLS policy on Worker Cluster 1 +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-1 apply -f config_files/peer-authentication.yaml + +# Apply strict mTLS policy on Worker Cluster 2 +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-2 apply -f config_files/peer-authentication.yaml +``` + +Expected output for each command: +``` +peerauthentication.security.istio.io/default created +authorizationpolicy.security.istio.io/bookinfo-allow created +``` + +### 7. Configure Authorization Policies + +Create authorization policies to allow necessary traffic: + +```bash +# Allow access to productpage +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-1 apply -f config_files/istio-rbac.yaml + +# Allow external traffic to the ingress gateway +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-1 apply -f config_files/istio-allow-ingress.yaml +``` + +Expected output: +``` +authorizationpolicy.security.istio.io/allow-productpage created +authorizationpolicy.security.istio.io/allow-ingress-gateway created +``` + +### 8. Verify Cross-Cluster Connectivity + +Check DNS resolution and connectivity from the productpage pod: + +```bash +# Get the productpage pod name +PRODUCTPAGE_POD=$(kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-1 get pods -n bookinfo -l app=productpage -o jsonpath='{.items[0].metadata.name}') + +# Exec into the pod to test connectivity +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-1 exec -it -n bookinfo $PRODUCTPAGE_POD -c netshoot -- /bin/bash +``` + +Once inside the pod, run these commands: + +```bash +# Test DNS resolution for details service +nslookup details + +# Test DNS resolution for reviews service +nslookup reviews + +# Test DNS resolution for ratings service +nslookup ratings +``` + +Expected output: +``` +Server: 127.0.0.1 +Address: 127.0.0.1#53 + +Name: details.bookinfo.svc.cluster.local +Address: 34.118.236.170 + +Server: 127.0.0.1 +Address: 127.0.0.1#53 + +Name: reviews.bookinfo.svc.cluster.local +Address: 34.118.231.183 + +Server: 127.0.0.1 +Address: 127.0.0.1#53 + +Name: ratings.bookinfo.svc.cluster.local +Address: 34.118.226.89 +``` + +Type `exit` to leave the pod. + +### 9. Optional: Ensure Certificate Trust Between Clusters + +To ensure mutual trust for mTLS between clusters, copy root certificates: + +```bash +# Copy root-cert from Cluster 1 to Cluster 2 +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-1 get configmap -n istio-system istio-ca-root-cert -o yaml | \ + sed 's/namespace: istio-system/namespace: kubeslice-system/' | \ + kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-2 apply -f - + +# Copy root-cert from Cluster 2 to Cluster 1 +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-2 get configmap -n istio-system istio-ca-root-cert -o yaml | \ + sed 's/namespace: istio-system/namespace: kubeslice-system/' | \ + kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-1 apply -f - +``` + +### 10. Verify mTLS Configuration + +Check PeerAuthentication policies on both clusters to confirm mTLS is enabled: + +```bash +# Check Worker Cluster 1 +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-1 get peerauthentication -n bookinfo -o yaml + +# Check Worker Cluster 2 +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-2 get peerauthentication -n bookinfo -o yaml +``` + +Expected output should show `mode: STRICT` in the spec section: +```yaml +apiVersion: v1 +items: +- apiVersion: security.istio.io/v1 + kind: PeerAuthentication + metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"security.istio.io/v1beta1","kind":"PeerAuthentication","metadata":{"annotations":{},"name":"default","namespace":"bookinfo"},"spec":{"mtls":{"mode":"STRICT"}}} + creationTimestamp: "2025-08-10T15:48:31Z" + generation: 1 + name: default + namespace: bookinfo + resourceVersion: "1754840911946783017" + uid: 9cf690b8-e895-455b-8d76-c875fdd9fa5e + spec: + mtls: + mode: STRICT +kind: List +metadata: + resourceVersion: "" +``` + +### 11. Access the Application + +Access the Bookinfo application using the Istio Ingress Gateway's external IP: + +```bash +# Get the Ingress Gateway IP +GATEWAY_IP=$(kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-1 get svc istio-ingress -n istio-system -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + +echo "Access the Bookinfo application at: http://$GATEWAY_IP/productpage" +``` + +### 12. Verify the Application UI + +Once you access the Bookinfo productpage through the Istio Ingress Gateway, you should see a page similar to the screenshot below: + +![Bookinfo Productpage Screenshot](./productpage-istio-gw.png) + +*Figure: Bookinfo Productpage served through Istio Ingress Gateway with mTLS enabled* + +## Troubleshooting + +### 1. ServiceImports Stuck in PENDING State + +If ServiceImports are stuck in PENDING state: + +```bash +# Check status +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-1 get serviceimports -n bookinfo +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-2 get serviceexports -n bookinfo + +# Delete and recreate the ServiceExport +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-2 delete serviceexport -n bookinfo +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-2 apply -f config_files/serviceexports.yaml -n bookinfo +``` + +### 2. Istio CRDs Not Installed + +If you encounter errors about missing Istio CRDs: + +```bash +# Install Istio using istioctl +istioctl install --set profile=demo --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-1 -y +istioctl install --set profile=demo --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-2 -y +``` + +### 3. Blank Productpage + +If the productpage shows a blank page or cannot be reached: + +```bash +# Check if the Istio Gateway is properly configured +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-1 get gateway -n bookinfo +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-1 get virtualservice -n bookinfo + +# Ensure authorization policies allow external traffic +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-1 apply -f config_files/istio-allow-ingress.yaml +``` + +## Conclusion + +You have successfully deployed the Bookinfo application across two KubeSlice-connected clusters with Istio service mesh and mTLS enabled. The application architecture provides: + +1. Secure service-to-service communication with mTLS +2. Cross-cluster service discovery via KubeSlice +3. External access through Istio Gateway + +For more details on the architecture and features, refer to the [README.md](./README.md). +istioctl install --set profile=demo --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-2 -y +``` + +### 3. Blank Productpage + +If the productpage shows a blank page or cannot be reached: + +```bash +# Check if the Istio Gateway is properly configured +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-1 get gateway -n bookinfo +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-1 get virtualservice -n bookinfo + +# Ensure authorization policies allow external traffic +kubectl --context=gke_graphic-transit-458312-f7_us-east1_ks-worker-1 apply -f config_files/istio-allow-ingress.yaml +``` + +## Conclusion + +You have successfully deployed the Bookinfo application across two KubeSlice-connected clusters with Istio service mesh and mTLS enabled. The application architecture provides: + +1. Secure service-to-service communication with mTLS +2. Cross-cluster service discovery via KubeSlice +3. External access through Istio Gateway + +For more details on the architecture and features, refer to the [README.md](./README.md). diff --git a/kind/bookinfo-istio/config_files/details.yaml b/kind/bookinfo-istio/config_files/details.yaml new file mode 100644 index 0000000..76a21c4 --- /dev/null +++ b/kind/bookinfo-istio/config_files/details.yaml @@ -0,0 +1,63 @@ +################################################################################################## +# Details service with Istio sidecar injection +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: details + labels: + app: details + service: details +spec: + ports: + - port: 9080 + name: http + selector: + app: details +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: bookinfo-details + labels: + account: details +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: details-v1 + labels: + app: details + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: details + version: v1 + template: + metadata: + labels: + app: details + version: v1 + annotations: + sidecar.istio.io/inject: "true" + spec: + serviceAccountName: bookinfo-details + containers: + - name: details + image: docker.io/istio/examples-bookinfo-details-v1:1.16.2 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 + securityContext: + runAsUser: 1000 + - name: netshoot + image: nicolaka/netshoot + imagePullPolicy: IfNotPresent + command: ["/bin/sleep", "3650d"] + securityContext: + capabilities: + add: ["NET_ADMIN"] + allowPrivilegeEscalation: true + privileged: true diff --git a/kind/bookinfo-istio/config_files/gateway.yaml b/kind/bookinfo-istio/config_files/gateway.yaml new file mode 100644 index 0000000..48dfd20 --- /dev/null +++ b/kind/bookinfo-istio/config_files/gateway.yaml @@ -0,0 +1,43 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: bookinfo-gateway + namespace: bookinfo +spec: + selector: + istio: ingressgateway # Use Istio default gateway implementation + servers: + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - "*" # Allow all hosts +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: bookinfo + namespace: bookinfo +spec: + hosts: + - "*" + gateways: + - bookinfo-gateway + http: + - match: + - uri: + exact: /productpage + - uri: + prefix: /static + - uri: + exact: /login + - uri: + exact: /logout + - uri: + prefix: /api/v1/products + route: + - destination: + host: productpage + port: + number: 9080 \ No newline at end of file diff --git a/kind/bookinfo-istio/config_files/istio-destination-rule.yml b/kind/bookinfo-istio/config_files/istio-destination-rule.yml new file mode 100644 index 0000000..f996085 --- /dev/null +++ b/kind/bookinfo-istio/config_files/istio-destination-rule.yml @@ -0,0 +1,32 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: details + namespace: bookinfo +spec: + host: details + trafficPolicy: + tls: + mode: ISTIO_MUTUAL +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: reviews + namespace: bookinfo +spec: + host: reviews + trafficPolicy: + tls: + mode: ISTIO_MUTUAL +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: ratings + namespace: bookinfo +spec: + host: ratings + trafficPolicy: + tls: + mode: ISTIO_MUTUAL \ No newline at end of file diff --git a/kind/bookinfo-istio/config_files/peer-authentication.yaml b/kind/bookinfo-istio/config_files/peer-authentication.yaml new file mode 100644 index 0000000..ad9e619 --- /dev/null +++ b/kind/bookinfo-istio/config_files/peer-authentication.yaml @@ -0,0 +1,46 @@ +# PeerAuthentication to enforce strict mTLS +apiVersion: security.istio.io/v1beta1 +kind: PeerAuthentication +metadata: + name: default + namespace: bookinfo +spec: + mtls: + mode: STRICT +--- +# AuthorizationPolicy to allow communication between bookinfo services +apiVersion: security.istio.io/v1beta1 +kind: AuthorizationPolicy +metadata: + name: bookinfo-policy + namespace: bookinfo +spec: + action: ALLOW + rules: + - from: + - source: + principals: ["cluster.local/ns/bookinfo/sa/bookinfo-productpage"] + to: + - operation: + methods: ["GET"] + - from: + - source: + principals: ["cluster.local/ns/bookinfo/sa/bookinfo-reviews"] + to: + - operation: + methods: ["GET"] + - from: + - source: + principals: ["cluster.local/ns/bookinfo/sa/bookinfo-details"] + to: + - operation: + methods: ["GET"] + - from: + - source: + principals: ["cluster.local/ns/bookinfo/sa/bookinfo-ratings"] + to: + - operation: + methods: ["GET"] + - from: + - source: + namespaces: ["istio-system"] diff --git a/kind/bookinfo-istio/config_files/productpage.yaml b/kind/bookinfo-istio/config_files/productpage.yaml new file mode 100644 index 0000000..192ff26 --- /dev/null +++ b/kind/bookinfo-istio/config_files/productpage.yaml @@ -0,0 +1,78 @@ +################################################################################################## +# Productpage service with Istio sidecar injection +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: productpage + namespace: bookinfo + labels: + app: productpage + service: productpage +spec: + type: NodePort + ports: + - port: 9080 + name: http + selector: + app: productpage +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: bookinfo-productpage + namespace: bookinfo + labels: + account: productpage +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: productpage-v1 + namespace: bookinfo + labels: + app: productpage + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: productpage + version: v1 + template: + metadata: + labels: + app: productpage + version: v1 + annotations: + sidecar.istio.io/inject: "true" + spec: + serviceAccountName: bookinfo-productpage + containers: + - name: productpage + image: docker.io/istio/examples-bookinfo-productpage-v1:1.16.2 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 + volumeMounts: + - name: tmp + mountPath: /tmp + securityContext: + runAsUser: 1000 + env: + - name: REVIEWS_HOSTNAME + value: reviews.bookinfo.svc.slice.local + - name: DETAILS_HOSTNAME + value: details.bookinfo.svc.slice.local + - name: netshoot + image: nicolaka/netshoot + imagePullPolicy: IfNotPresent + command: ["/bin/sleep", "3650d"] + securityContext: + capabilities: + add: ["NET_ADMIN"] + allowPrivilegeEscalation: true + privileged: true + volumes: + - name: tmp + emptyDir: {} diff --git a/kind/bookinfo-istio/config_files/ratings.yaml b/kind/bookinfo-istio/config_files/ratings.yaml new file mode 100644 index 0000000..e300edf --- /dev/null +++ b/kind/bookinfo-istio/config_files/ratings.yaml @@ -0,0 +1,63 @@ +################################################################################################## +# Ratings service with Istio sidecar injection +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: ratings + labels: + app: ratings + service: ratings +spec: + ports: + - port: 9080 + name: http + selector: + app: ratings +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: bookinfo-ratings + labels: + account: ratings +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ratings-v1 + labels: + app: ratings + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: ratings + version: v1 + template: + metadata: + labels: + app: ratings + version: v1 + annotations: + sidecar.istio.io/inject: "true" + spec: + serviceAccountName: bookinfo-ratings + containers: + - name: ratings + image: docker.io/istio/examples-bookinfo-ratings-v1:1.16.2 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 + securityContext: + runAsUser: 1000 + - name: netshoot + image: nicolaka/netshoot + imagePullPolicy: IfNotPresent + command: ["/bin/sleep", "3650d"] + securityContext: + capabilities: + add: ["NET_ADMIN"] + allowPrivilegeEscalation: true + privileged: true diff --git a/kind/bookinfo-istio/config_files/reviews.yaml b/kind/bookinfo-istio/config_files/reviews.yaml new file mode 100644 index 0000000..f5b3b57 --- /dev/null +++ b/kind/bookinfo-istio/config_files/reviews.yaml @@ -0,0 +1,76 @@ +################################################################################################## +# Reviews service with Istio sidecar injection +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: reviews + labels: + app: reviews + service: reviews +spec: + ports: + - port: 9080 + name: http + selector: + app: reviews +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: bookinfo-reviews + labels: + account: reviews +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: reviews-v3 + labels: + app: reviews + version: v3 +spec: + replicas: 1 + selector: + matchLabels: + app: reviews + version: v3 + template: + metadata: + labels: + app: reviews + version: v3 + annotations: + sidecar.istio.io/inject: "true" + spec: + serviceAccountName: bookinfo-reviews + containers: + - name: reviews + image: docker.io/istio/examples-bookinfo-reviews-v3:1.16.2 + imagePullPolicy: IfNotPresent + env: + - name: LOG_DIR + value: "/tmp/logs" + ports: + - containerPort: 9080 + volumeMounts: + - name: tmp + mountPath: /tmp + - name: wlp-output + mountPath: /opt/ibm/wlp/output + securityContext: + runAsUser: 1000 + - name: netshoot + image: nicolaka/netshoot + imagePullPolicy: IfNotPresent + command: ["/bin/sleep", "3650d"] + securityContext: + capabilities: + add: ["NET_ADMIN"] + allowPrivilegeEscalation: true + privileged: true + volumes: + - name: wlp-output + emptyDir: {} + - name: tmp + emptyDir: {} diff --git a/kind/bookinfo-istio/config_files/serviceexports.yaml b/kind/bookinfo-istio/config_files/serviceexports.yaml new file mode 100644 index 0000000..ac9b25b --- /dev/null +++ b/kind/bookinfo-istio/config_files/serviceexports.yaml @@ -0,0 +1,56 @@ +################################################################################## +# Details ServiceExport +################################################################################## +apiVersion: networking.kubeslice.io/v1beta1 +kind: ServiceExport +metadata: + name: details + namespace: bookinfo +spec: + slice: bookinfo-slice #Replace Slice Name + selector: + matchLabels: + app: details + ingressEnabled: true + ports: + - name: http + containerPort: 9080 + protocol: TCP +--- +################################################################################## +# Reviews ServiceExport +################################################################################## +apiVersion: networking.kubeslice.io/v1beta1 +kind: ServiceExport +metadata: + name: reviews + namespace: bookinfo +spec: + slice: bookinfo-slice #Replace Slice Name + selector: + matchLabels: + app: reviews + ingressEnabled: true + ports: + - name: http + containerPort: 9080 + protocol: TCP +--- +################################################################################## +# Ratings ServiceExport +################################################################################## +apiVersion: networking.kubeslice.io/v1beta1 +kind: ServiceExport +metadata: + name: ratings + namespace: bookinfo +spec: + slice: bookinfo-slice #Replace Slice Name + selector: + matchLabels: + app: ratings + ingressEnabled: true + ports: + - name: http + containerPort: 9080 + protocol: TCP diff --git a/kind/bookinfo-istio/config_files/slice-config.yaml b/kind/bookinfo-istio/config_files/slice-config.yaml new file mode 100644 index 0000000..33c56b8 --- /dev/null +++ b/kind/bookinfo-istio/config_files/slice-config.yaml @@ -0,0 +1,54 @@ +apiVersion: controller.kubeslice.io/v1alpha1 +kind: SliceConfig +metadata: + name: bookinfo-slice + namespace: kubeslice-kubeslice-avesha +spec: + sliceSubnet: 10.1.0.0/16 + sliceType: Application + sliceGatewayProvider: + sliceGatewayType: OpenVPN + sliceCaType: Local + sliceIpamType: Local + clusters: + - ks-worker-1 + - ks-worker-2 + qosProfileDetails: + queueType: HTB + priority: 1 + tcType: BANDWIDTH_CONTROL + bandwidthCeilingKbps: 5120 + bandwidthGuaranteedKbps: 2560 + dscpClass: AF11 + namespaceIsolationProfile: + applicationNamespaces: + - namespace: bookinfo + clusters: + - '*' + - namespace: istio-system + clusters: + - '*' + isolationEnabled: false # Set to true if you want strict namespace isolation + allowedNamespaces: + - namespace: kube-system + clusters: + - '*' + externalGatewayConfig: + - ingress: + enabled: true + egress: + enabled: false + nsIngress: + enabled: false + gatewayType: istio + clusters: + - ks-worker-1 # Product cluster with productpage service + - ingress: + enabled: false + egress: + enabled: true + nsIngress: + enabled: false + gatewayType: istio + clusters: + - ks-worker-2 # Services cluster with details, reviews, ratings \ No newline at end of file diff --git a/kind/bookinfo-istio/productpage-istio-gw.png b/kind/bookinfo-istio/productpage-istio-gw.png new file mode 100644 index 0000000..668c30e Binary files /dev/null and b/kind/bookinfo-istio/productpage-istio-gw.png differ diff --git a/kind/bookinfo-istio/utils/cleanup.sh b/kind/bookinfo-istio/utils/cleanup.sh new file mode 100755 index 0000000..4914a6a --- /dev/null +++ b/kind/bookinfo-istio/utils/cleanup.sh @@ -0,0 +1,119 @@ +#!/bin/bash + +set -e + +BASE_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +CONFIG_FILE=${BASE_DIR}/../kind.env + +if [[ -f $CONFIG_FILE ]]; then + source $CONFIG_FILE +else + echo "File $CONFIG_FILE not found" + exit 1 +fi + +# Define cluster contexts +PRODUCT_CLUSTER="${PREFIX}${WORKERS[0]}" +SERVICES_CLUSTER="${PREFIX}${WORKERS[1]}" + +# Use generic contexts if the script is run in an environment without the prefix +if [[ -z "$PRODUCT_CLUSTER" ]]; then + PRODUCT_CLUSTER="cluster1" + SERVICES_CLUSTER="cluster2" +fi + +echo "==== Starting Bookinfo-Istio Cleanup ====" +echo "Product Cluster: $PRODUCT_CLUSTER" +echo "Services Cluster: $SERVICES_CLUSTER" +echo "" + +# Function to remove resources from a specific cluster +cleanup_cluster() { + local cluster=$1 + echo "Cleaning up resources in $cluster..." + + # Switch context to the cluster + kubectl config use-context $cluster + + # Remove authorization policies + echo "Removing Authorization Policies..." + kubectl delete authorizationpolicy --all -n bookinfo 2>/dev/null || true + + # Remove peer authentication + echo "Removing Peer Authentication..." + kubectl delete peerauthentication --all -n bookinfo 2>/dev/null || true + + # Remove Istio Gateway and VirtualService + if [[ "$cluster" == "$PRODUCT_CLUSTER" ]]; then + echo "Removing Istio Gateway and VirtualService..." + kubectl delete gateway --all -n bookinfo 2>/dev/null || true + kubectl delete virtualservice --all -n bookinfo 2>/dev/null || true + fi + + # Remove ServiceExports + echo "Removing ServiceExports..." + kubectl delete serviceexports.networking.kubeslice.io --all -n bookinfo 2>/dev/null || true + + # Remove Bookinfo deployments and services + echo "Removing Bookinfo deployments and services..." + kubectl delete deployment --all -n bookinfo 2>/dev/null || true + kubectl delete service --all -n bookinfo 2>/dev/null || true + + # Remove Bookinfo ServiceAccounts + echo "Removing Bookinfo ServiceAccounts..." + kubectl delete serviceaccount --all -n bookinfo 2>/dev/null || true + + # Delete the bookinfo namespace last + echo "Removing bookinfo namespace..." + kubectl delete namespace bookinfo --grace-period=0 --force 2>/dev/null || true + + echo "Cleanup completed for $cluster" + echo "" +} + +# Cleanup Istio resources +cleanup_istio() { + local cluster=$1 + echo "Cleaning up Istio from $cluster (optional)..." + + kubectl config use-context $cluster + + # Check if istioctl is available + if command -v istioctl &> /dev/null; then + echo "Using istioctl to remove Istio..." + istioctl uninstall --purge -y 2>/dev/null || true + else + echo "istioctl not found, removing Istio resources manually..." + kubectl delete namespace istio-system --grace-period=0 --force 2>/dev/null || true + fi + + echo "Istio cleanup completed for $cluster" + echo "" +} + +# Ask user if they want to cleanup just Bookinfo or also Istio +read -p "Do you want to remove Istio as well? (y/n, default: n): " remove_istio +remove_istio=${remove_istio:-n} + +# Clean up both clusters +cleanup_cluster $PRODUCT_CLUSTER +cleanup_cluster $SERVICES_CLUSTER + +# Optionally clean up Istio +if [[ "$remove_istio" == "y" ]]; then + cleanup_istio $PRODUCT_CLUSTER + cleanup_istio $SERVICES_CLUSTER +fi + +echo "==== Bookinfo-Istio Cleanup Complete ====" +echo "All Bookinfo resources have been removed from both clusters." +if [[ "$remove_istio" == "y" ]]; then + echo "Istio has also been removed." +else + echo "Istio is still installed. To remove it later, use 'istioctl uninstall --purge' or run this script again." +fi +echo "" +echo "To remove the KubeSlice slice, use the kubeslice controller commands." +echo "For example: kubectl delete sliceconfig convoy -n kubeslice-system" + +chmod +x $BASE_DIR/cleanup.sh diff --git a/kind/bookinfo-istio/utils/verify_mtls.sh b/kind/bookinfo-istio/utils/verify_mtls.sh new file mode 100755 index 0000000..f5a7be7 --- /dev/null +++ b/kind/bookinfo-istio/utils/verify_mtls.sh @@ -0,0 +1,176 @@ +#!/bin/bash + +# Script to verify mTLS is working between services + +set -e + +BASE_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +CONFIG_FILE=${BASE_DIR}/../../kind.env + +if [[ -f $CONFIG_FILE ]]; then + source $CONFIG_FILE +else + echo "File $CONFIG_FILE not found" + exit 1 +fi + +PRODUCT_CLUSTER="${PREFIX}${WORKERS[0]}" +SERVICES_CLUSTER="${PREFIX}${WORKERS[1]}" + +echo "=== mTLS Verification Script ===" + +verify_certificates() { + local cluster=$1 + local app=$2 + + echo "Checking certificates for $app on $cluster..." + kubectx $cluster + + POD=$(kubectl get pods -n bookinfo -l app=$app -o jsonpath='{.items[0].metadata.name}' 2>/dev/null) + if [[ -z "$POD" ]]; then + echo "✗ No pod found for app=$app" + return 1 + fi + + echo "Pod: $POD" + + # Check if istio-proxy container exists + if ! kubectl get pod $POD -n bookinfo -o jsonpath='{.spec.containers[*].name}' | grep -q istio-proxy; then + echo "✗ istio-proxy container not found" + return 1 + fi + + # Check certificates in the istio-proxy + echo "Checking certificates in istio-proxy..." + CERT_COUNT=$(kubectl exec -n bookinfo $POD -c istio-proxy -- sh -c 'find /etc/ssl/certs -name "*.pem" | wc -l' 2>/dev/null || echo "0") + echo "Certificate files found: $CERT_COUNT" + + # Check Envoy config for mTLS + echo "Checking Envoy configuration for mTLS..." + TLS_CONFIG=$(kubectl exec -n bookinfo $POD -c istio-proxy -- sh -c 'curl -s localhost:15000/config_dump | grep -c "tls_context"' 2>/dev/null || echo "0") + echo "TLS contexts found: $TLS_CONFIG" + + if [[ "$TLS_CONFIG" -gt 0 ]]; then + echo "✓ $app has mTLS configuration" + else + echo "⚠ $app may not have mTLS properly configured" + fi +} + +test_mtls_communication() { + echo "Testing mTLS communication between services..." + + kubectx $PRODUCT_CLUSTER + PRODUCTPAGE_POD=$(kubectl get pods -n bookinfo -l app=productpage -o jsonpath='{.items[0].metadata.name}') + + if [[ -z "$PRODUCTPAGE_POD" ]]; then + echo "✗ Productpage pod not found" + return 1 + fi + + echo "Testing connection to reviews service with mTLS..." + # Try to connect through Envoy proxy + REVIEWS_TEST=$(kubectl exec -n bookinfo $PRODUCTPAGE_POD -c productpage -- sh -c 'curl -s -w "%{http_code}" -o /dev/null http://reviews.bookinfo.svc.slice.local:9080/reviews/0' 2>/dev/null || echo "000") + + if [[ "$REVIEWS_TEST" == "200" ]]; then + echo "✓ mTLS connection to reviews service successful" + else + echo "⚠ mTLS connection to reviews service returned: $REVIEWS_TEST" + fi + + echo "Testing connection to details service with mTLS..." + DETAILS_TEST=$(kubectl exec -n bookinfo $PRODUCTPAGE_POD -c productpage -- sh -c 'curl -s -w "%{http_code}" -o /dev/null http://details.bookinfo.svc.slice.local:9080/details/0' 2>/dev/null || echo "000") + + if [[ "$DETAILS_TEST" == "200" ]]; then + echo "✓ mTLS connection to details service successful" + else + echo "⚠ mTLS connection to details service returned: $DETAILS_TEST" + fi +} + +check_peer_authentication() { + echo "Checking PeerAuthentication policies..." + + for cluster in $PRODUCT_CLUSTER $SERVICES_CLUSTER; do + echo "Cluster: $cluster" + kubectx $cluster + + if kubectl get peerauthentication default -n bookinfo &>/dev/null; then + MODE=$(kubectl get peerauthentication default -n bookinfo -o jsonpath='{.spec.mtls.mode}') + echo "✓ PeerAuthentication mode: $MODE" + else + echo "✗ PeerAuthentication not found" + fi + done +} + +main() { + echo "Starting mTLS verification..." + echo "" + + check_peer_authentication + echo "" + + verify_certificates $PRODUCT_CLUSTER "productpage" + echo "" + + verify_certificates $SERVICES_CLUSTER "details" + echo "" + + verify_certificates $SERVICES_CLUSTER "reviews" + echo "" + + verify_certificates $SERVICES_CLUSTER "ratings" + echo "" + + test_mtls_communication + echo "" + + echo "=== mTLS Verification Complete ===" +} + +CLUSTERS=("cluster1" "cluster2") + +echo "=== Verifying mTLS Configuration ===" +echo + +for cluster in "${CLUSTERS[@]}"; do + echo "Checking cluster: $cluster" + echo "---------------------------------" + + # Check PeerAuthentication policy + echo "PeerAuthentication policy:" + kubectl --context=$cluster get peerauthentication -n bookinfo + + # Get a pod with istio-proxy for verification + POD=$(kubectl --context=$cluster get pod -n bookinfo -l app=productpage -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || \ + kubectl --context=$cluster get pod -n bookinfo -l app=details -o jsonpath='{.items[0].metadata.name}' 2>/dev/null) + + if [ -n "$POD" ]; then + echo + echo "Checking mTLS certificates in pod $POD:" + kubectl --context=$cluster exec -n bookinfo $POD -c istio-proxy -- pilot-agent request GET stats | grep ssl_context + + echo + echo "Verifying Envoy is configured for mTLS:" + kubectl --context=$cluster exec -n bookinfo $POD -c istio-proxy -- curl -s localhost:15000/config_dump | grep -o "\"tls_inspector\"\|\"transport_socket\"" | sort | uniq -c + + echo + echo "Checking upstream TLS configuration:" + kubectl --context=$cluster exec -n bookinfo $POD -c istio-proxy -- curl -s localhost:15000/config_dump | grep '"alpn_protocols": \["istio"\]' -B 5 -A 5 | head -n 15 + else + echo "No pods with istio-proxy found in namespace bookinfo" + fi + + echo + echo "Checking for Authorization Policies:" + kubectl --context=$cluster get authorizationpolicies -n bookinfo + + echo + echo "---------------------------------" + echo +done + +echo "=== mTLS Verification Complete ===" + +main \ No newline at end of file