|
1 | 1 | # ziti-k8s-agent |
2 | 2 |
|
3 | | -The agent injects a sidecar that runs a Ziti tunneler as a bi-directional proxy and nameserver for Ziti services. You may enable sidecars for all pods in a namespace or specifc pods in any namespace. For each, the agent will manage the life cycle of a Ziti identity with the roles you specify in a pod annotation. |
| 3 | +The Ziti Kubernetes Agent injects a sidecar that runs a Ziti tunneler as a bi-directional proxy and nameserver for Ziti services. You may enable sidecars for all pods in a namespace or specific pods in any namespace. For each, the agent will manage the life cycle of a Ziti identity with the roles you specify in a pod annotation. |
4 | 4 |
|
5 | | -## Namespace |
| 5 | +## Installation |
6 | 6 |
|
7 | | -A namespace will not be created. The agent may be installed in any existing namespace. |
| 7 | +### Prerequisites |
8 | 8 |
|
9 | | -## Select Pods for Sidecar Injection |
| 9 | +- Kubernetes cluster with cert-manager installed |
| 10 | +- Ziti Controller with admin identity credentials |
| 11 | +- Helm 3.x |
| 12 | + |
| 13 | +### Install with Helm |
| 14 | + |
| 15 | +```bash |
| 16 | +# install chart directly from source |
| 17 | +git clone https://github.com/netfoundry/ziti-k8s-agent.git |
| 18 | +cd ziti-k8s-agent |
| 19 | +``` |
10 | 20 |
|
11 | | -Choose a method to select the pods: namespace, pod, or both. The sidecar is injected only on pod creation. |
| 21 | +#### Option 1: Existing Secret (PREFERRED FOR SECURITY) |
12 | 22 |
|
13 | | -### Select by Namespace |
| 23 | +> **⚠️ SECURITY WARNING**: This webhook requires a Ziti admin identity with full network privileges. Handle with extreme care! |
14 | 24 |
|
15 | | -Select all pods in namespaces labeled `tunnel.openziti.io/enabled="true"`. |
| 25 | +Create a secret containing your complete Ziti identity JSON configuration: |
16 | 26 |
|
17 | 27 | ```bash |
18 | | -kubectl label namespace {name} tunnel.openziti.io/enabled="true" |
| 28 | +# Create secret from enrolled identity JSON file |
| 29 | +kubectl create secret generic netfoundry-admin-identity \ |
| 30 | + --from-file=netfoundry-admin.json=netfoundry-admin.json \ |
| 31 | + --namespace=netfoundry-system |
| 32 | + |
| 33 | +# Install webhook |
| 34 | +helm upgrade --install ziti-webhook ./charts/ziti-webhook \ |
| 35 | + --set identity.existingSecret.name="netfoundry-admin-identity" |
| 36 | + |
| 37 | +#### Option 2: Chart-Managed Secret (FOR DEVELOPMENT/TESTING ONLY) |
| 38 | + |
| 39 | +> **⚠️ EXTREME SECURITY WARNING**: Option 2 embeds the complete admin identity in Helm values, which may be stored in version control or Helm history. This exposes full network administrative credentials. Use ONLY for development/testing environments! |
| 40 | + |
| 41 | +Provide the complete identity JSON directly via Helm values: |
| 42 | + |
| 43 | +```bash |
| 44 | +# Read the identity JSON and provide it directly |
| 45 | +# Using --set-json validates the JSON syntax immediately |
| 46 | +helm upgrade --install ziti-webhook ./charts/ziti-webhook \ |
| 47 | + --set-json identity.json="$(< netfoundry-admin.json)" |
19 | 48 | ``` |
20 | 49 |
|
21 | | -The agent manifest must reflect your choice to select by namespace. Setting `SIDECAR_SELECTORS="namespace"` in the script's environment before generating the manifest will configure the mutating webhook with a `namespaceSelector`. |
| 50 | +## Select Pods for Sidecar Injection |
| 51 | + |
| 52 | +### Select by Namespace (Default) |
22 | 53 |
|
23 | | -The `kube-system` namespace is excluded based on the advice in this [Kubernetes documentation](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#avoiding-operating-on-the-kube-system-namespace). |
| 54 | +Select all pods in namespaces labeled `tunnel.openziti.io/enabled="true"`: |
| 55 | + |
| 56 | +```bash |
| 57 | +# Label namespace for sidecar injection |
| 58 | +kubectl label namespace {name} tunnel.openziti.io/enabled="true" |
| 59 | +
|
| 60 | +# Install webhook with namespace selector (default) |
| 61 | +helm upgrade --install ziti-webhook ./charts/ziti-webhook \ |
| 62 | + --set identity.existingSecret.name="netfoundry-admin-identity" \ |
| 63 | + --set webhook.selectors.enabled="namespace" |
| 64 | +``` |
24 | 65 |
|
25 | 66 | ### Select by Pod |
26 | 67 |
|
27 | | -Select pods labeled `tunnel.openziti.io/enabled="true"` in any namespace. |
| 68 | +Select pods labeled `tunnel.openziti.io/enabled="true"` in any namespace: |
28 | 69 |
|
29 | 70 | ```bash |
| 71 | +# Label deployment for sidecar injection |
30 | 72 | kubectl patch deployment/{name} -p '{"spec":{"template":{"metadata":{"labels":{"tunnel.openziti.io/enabled":"true"}}}}}' |
31 | | -``` |
32 | 73 |
|
33 | | -The agent manifest must reflect your choice to select by pod. Setting `SIDECAR_SELECTORS="pod"` in the script's environment before generating the manifest will configure the mutating webhook with an `objectSelector`. |
| 74 | +# Install webhook with pod selector |
| 75 | +helm install ziti-webhook ./charts/ziti-webhook \ |
| 76 | + --set identity.existingSecret.name="netfoundry-admin-identity" \ |
| 77 | + --set webhook.selectors.enabled="pod" |
| 78 | +``` |
34 | 79 |
|
35 | 80 | ### Select by Namespace and Pod |
36 | 81 |
|
37 | | -Select pods labeled `tunnel.openziti.io/enabled="true"` only in namespaces labeled `tunnel.openziti.io/enabled="true"`. |
38 | | - |
39 | | -The agent manifest must reflect your choice to select by pod. Setting `SIDECAR_SELECTORS="namespace,pod"` in the script's environment before generating the manifest will configure the mutating webhook with both `namespaceSelector` and `objectSelector`. Both selectors must match for a pod to be selected. |
| 82 | +Select pods labeled `tunnel.openziti.io/enabled="true"` only in namespaces labeled `tunnel.openziti.io/enabled="true"`: |
40 | 83 |
|
41 | 84 | ```bash |
| 85 | +# Label both namespace and deployment |
42 | 86 | kubectl label namespace "default" tunnel.openziti.io/enabled="true" |
| 87 | +kubectl patch deployment/{name} -p '{"spec":{"template":{"metadata":{"labels":{"tunnel.openziti.io/enabled":"true"}}}}}' |
| 88 | +
|
| 89 | +# Install webhook with both selectors |
| 90 | +helm upgrade --install ziti-webhook ./charts/ziti-webhook \ |
| 91 | + --set identity.existingSecret.name="netfoundry-admin-identity" \ |
| 92 | + --set webhook.selectors.enabled="namespace,pod" |
43 | 93 | ``` |
44 | 94 |
|
| 95 | +**Note**: The `kube-system` namespace is excluded based on [Kubernetes best practices](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#avoiding-operating-on-the-kube-system-namespace). |
| 96 | + |
45 | 97 | ## Specify Ziti roles for Pod Identities |
46 | 98 |
|
47 | 99 | The Ziti agent will generate a default Ziti identity role based on the app label unless you annotate it with a comma-separated list of roles. This example adds the role `acme-api-clients` to the Ziti identity shared by all replicas of the deployment. Updating the running pod's annotation will update the Ziti identity role. |
@@ -70,57 +122,105 @@ Pods authorized to bind a Ziti service require that service to have a host addre |
70 | 122 |
|
71 | 123 | ### Prerequisities |
72 | 124 |
|
73 | | -1. an OpenZiti network - either NetFoundry Cloud or self-hosted |
| 125 | +1. an OpenZiti network - either NetFoundry Cloud, NetFoundry On-Premises, or self-hosted |
74 | 126 | 1. A JSON identity configuration file for an OpenZiti identity with the admin privilege |
75 | 127 | 1. A K8S namespace in which to deploy the agent |
76 | 128 |
|
77 | | -### Set Optional Environment Variables |
| 129 | +## Advanced Configuration |
78 | 130 |
|
79 | | -These optional variables will override defaults. |
| 131 | +### Custom Values File |
80 | 132 |
|
81 | | -```bash |
82 | | -# Namespace configuration |
83 | | -export ZITI_AGENT_NAMESPACE="default" # Namespace to deploy the agent |
84 | | -export CLUSTER_DNS_ZONE="cluster.local" # Kubernetes cluster DNS zone |
85 | | - |
86 | | -# Agent image configuration |
87 | | -export ZITI_AGENT_IMAGE="docker.io/netfoundry/ziti-k8s-agent" # Agent container image |
88 | | -export ZITI_AGENT_IMAGE_PULL_POLICY="IfNotPresent" # Pull policy for agent image |
89 | | -export ZITI_AGENT_LOG_LEVEL="2" # Log level for agent (0-5) |
90 | | - |
91 | | -# Sidecar configuration |
92 | | -export SIDECAR_IMAGE="docker.io/openziti/ziti-tunnel" # Sidecar container image |
93 | | -export SIDECAR_IMAGE_VERSION="latest" # Sidecar image version |
94 | | -export SIDECAR_IMAGE_PULL_POLICY="IfNotPresent" # Pull policy for sidecar image |
95 | | - |
96 | | -# Resource configuration |
97 | | -export ZITI_AGENT_CPU="100m" # CPU request for agent |
98 | | -export ZITI_AGENT_MEMORY="128Mi" # Memory request for agent |
99 | | -export ZITI_AGENT_CPU_LIMIT="500m" # CPU limit for agent |
100 | | -export ZITI_AGENT_MEMORY_LIMIT="512Mi" # Memory limit for agent |
101 | | - |
102 | | -# Webhook configuration |
103 | | -export ZITI_AGENT_WEBHOOK_FAILURE_POLICY="Fail" # How webhook failures are handled (Fail or Ignore) |
104 | | - |
105 | | -# DNS configuration |
106 | | -export SEARCH_DOMAINS="" # Space-separated list of DNS search domains |
| 133 | +For complex deployments, create a custom values file: |
| 134 | +
|
| 135 | +```yaml |
| 136 | +# values-production.yaml |
| 137 | +controller: |
| 138 | + # Optional - if not specified, will be inferred from identity configuration |
| 139 | + mgmtApi: "https://ctrl0.ziti.example.com:1280/edge/management/v1" |
| 140 | +
|
| 141 | +deployment: |
| 142 | + image: |
| 143 | + repo: "docker.io/netfoundry/ziti-k8s-agent" |
| 144 | + tag: "v1.2.3" |
| 145 | + pullPolicy: "IfNotPresent" |
| 146 | + replicas: 2 |
| 147 | + resources: |
| 148 | + requests: |
| 149 | + cpu: "200m" |
| 150 | + memory: "256Mi" |
| 151 | + limits: |
| 152 | + cpu: "1000m" |
| 153 | + memory: "1Gi" |
| 154 | +
|
| 155 | +sidecar: |
| 156 | + image: |
| 157 | + repo: "docker.io/openziti/ziti-tunnel" |
| 158 | + tag: "v0.23.0" |
| 159 | + pullPolicy: "IfNotPresent" |
| 160 | + # Custom DNS search domains for injected pods |
| 161 | + searchDomains: |
| 162 | + - "ziti.internal" |
| 163 | + - "ziti.example.com" |
| 164 | + dnsUpstreamEnabled: true |
| 165 | + dnsUnanswerable: "refused" |
| 166 | +
|
| 167 | +server: |
| 168 | + port: 9443 |
| 169 | + logLevel: 2 # 0=errors, 1=info, 2=detailed, 3=debug, 4=trace |
| 170 | +
|
| 171 | +webhook: |
| 172 | + selectors: |
| 173 | + enabled: "namespace,pod" # Both namespace and pod selectors |
| 174 | + failurePolicy: "Fail" |
| 175 | +
|
| 176 | +# Custom cluster DNS configuration |
| 177 | +clusterDns: |
| 178 | + zone: "cluster.local" |
| 179 | +
|
| 180 | +# Identity configuration (use existing secret for production) |
| 181 | +identity: |
| 182 | + existingSecret: |
| 183 | + name: "netfoundry-admin-identity" |
| 184 | + key: "netfoundry-admin.json" |
107 | 185 | ``` |
108 | 186 |
|
109 | | -You may replace the cluster's default DNS search domains for selected pods by exporting `SEARCH_DOMAINS` as a space separated list of domain name suffixes. This may be useful if the selected pods never need to resolve the names of cluster services, but do need to resolve short names in a DNS zone that you control outside of the cluster, e.g., `ziti.internal ziti.example.com`. |
| 187 | +### Install with Custom Values |
110 | 188 |
|
111 | | -### Generate a Manifest |
| 189 | +```bash |
| 190 | +# Install with custom values file |
| 191 | +helm upgrade --install ziti-webhook ./charts/ziti-webhook \ |
| 192 | + --namespace=ziti-system \ |
| 193 | + --create-namespace \ |
| 194 | + --values=values-production.yaml |
| 195 | +
|
| 196 | +# Or override specific values inline |
| 197 | +helm upgrade --install ziti-webhook ./charts/ziti-webhook \ |
| 198 | + --set identity.existingSecret.name="netfoundry-admin-identity" \ |
| 199 | + --set deployment.replicas=3 \ |
| 200 | + --set server.logLevel=4 \ |
| 201 | + --set sidecar.searchDomains="{ziti.internal,ziti.example.com}" \ |
| 202 | + --set webhook.selectors.enabled="namespace,pod" |
| 203 | +``` |
112 | 204 |
|
113 | | -Required environment variables: |
| 205 | +### DNS Search Domains |
114 | 206 |
|
115 | | -- `IDENTITY_FILE` - path to the JSON file from the admin identity enrollment step |
116 | | -- `SIDECAR_SELECTORS` - comma-separated list of methods by which pods are selected for sidecar injection: `namespace`, `pod`, or both (see [Select Pods for Sidecar Injection](#select-pods-for-sidecar-injection) above) |
| 207 | +You may replace the cluster's default DNS search domains for selected pods by configuring `sidecar.searchDomains`. This is useful when selected pods need to resolve short names in DNS zones outside the cluster: |
117 | 208 |
|
118 | 209 | ```bash |
119 | | -IDENTITY_FILE="ziti-k8s-agent.json" SIDECAR_SELECTORS="namespace,pod" ./generate-ziti-agent-manifest.bash > ./ziti-agent.yaml |
| 210 | +helm upgrade --install ziti-webhook ./charts/ziti-webhook \ |
| 211 | + --set identity.existingSecret.name="netfoundry-admin-identity" \ |
| 212 | + --set sidecar.searchDomains="{ziti.internal,ziti.example.com}" |
120 | 213 | ``` |
121 | 214 |
|
122 | | -### Apply the Manifest |
| 215 | +### Resource Management |
| 216 | + |
| 217 | +Configure resource requests and limits for production deployments: |
123 | 218 |
|
124 | 219 | ```bash |
125 | | -kubectl create -f ./ziti-agent.yaml |
| 220 | +helm upgrade --install ziti-webhook ./charts/ziti-webhook \ |
| 221 | + --set identity.existingSecret.name="netfoundry-admin-identity" \ |
| 222 | + --set deployment.resources.requests.cpu="200m" \ |
| 223 | + --set deployment.resources.requests.memory="256Mi" \ |
| 224 | + --set deployment.resources.limits.cpu="1000m" \ |
| 225 | + --set deployment.resources.limits.memory="1Gi" |
126 | 226 | ``` |
0 commit comments