Skip to content

Commit 6ba2cbb

Browse files
authored
Merge pull request #50 from netfoundry/add-helm-and-config-loader
Add helm chart and config loader
2 parents a569a57 + 037fc6f commit 6ba2cbb

File tree

22 files changed

+1720
-677
lines changed

22 files changed

+1720
-677
lines changed

.github/actions/eks-cluster-cleanup/action.yml

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,28 @@ runs:
5757
STATUS=$(get_cluster_status)
5858
5959
if [[ "$STATUS" == "NOT_FOUND" ]]; then
60-
echo "Cluster does not exist, nothing to delete"
60+
echo "Cluster does not exist, checking for orphaned CloudFormation stacks..."
61+
62+
# Clean up any orphaned CloudFormation stacks
63+
STACK_PREFIX="eksctl-${{ inputs.cluster_name }}"
64+
STACKS=$(aws cloudformation list-stacks \
65+
--region "${{ inputs.region }}" \
66+
--stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE DELETE_FAILED \
67+
--query "StackSummaries[?starts_with(StackName, '${STACK_PREFIX}')].StackName" \
68+
--output text)
69+
70+
if [[ -n "$STACKS" ]]; then
71+
echo "Found orphaned stacks: $STACKS"
72+
for STACK in $STACKS; do
73+
echo "Deleting orphaned stack: $STACK"
74+
aws cloudformation delete-stack --stack-name "$STACK" --region "${{ inputs.region }}" || true
75+
done
76+
echo "Initiated deletion of orphaned stacks, waiting 30s..."
77+
sleep 30
78+
else
79+
echo "No orphaned stacks found"
80+
fi
81+
6182
exit 0
6283
fi
6384
@@ -75,8 +96,34 @@ runs:
7596
fi
7697
7798
# Check for specific error conditions
78-
if grep -q "try again later\|ResourceInUseException\|cluster is currently being\|InvalidParameterException" /tmp/eksctl_delete.log; then
99+
if grep -q "try again later\|ResourceInUseException\|cluster is currently being\|InvalidParameterException\|DELETE_FAILED\|found the following undeleted stacks" /tmp/eksctl_delete.log; then
79100
echo "Received retryable error, waiting before next attempt..."
101+
if grep -q "DELETE_FAILED" /tmp/eksctl_delete.log || grep -q "found the following undeleted stacks" /tmp/eksctl_delete.log; then
102+
echo "Attempting to clean up nodegroup stacks that failed deletion"
103+
STACK_PREFIX="eksctl-${{ inputs.cluster_name }}"
104+
STACKS=$(aws cloudformation list-stacks \
105+
--region "${{ inputs.region }}" \
106+
--stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE DELETE_FAILED \
107+
--query "StackSummaries[?starts_with(StackName, '${STACK_PREFIX}')].StackName" \
108+
--output text)
109+
if [[ -n "$STACKS" ]]; then
110+
echo "Retry cleanup: found stacks $STACKS"
111+
for STACK in $STACKS; do
112+
echo "Retry cleanup: deleting $STACK"
113+
aws cloudformation update-termination-protection \
114+
--stack-name "$STACK" \
115+
--no-enable-termination-protection \
116+
--region "${{ inputs.region }}" || true
117+
aws cloudformation delete-stack --stack-name "$STACK" --region "${{ inputs.region }}" || true
118+
echo "Waiting for stack $STACK to reach DELETE_COMPLETE"
119+
aws cloudformation wait stack-delete-complete \
120+
--stack-name "$STACK" \
121+
--region "${{ inputs.region }}" && echo "Stack $STACK deleted" || echo "Stack $STACK still deleting or already removed"
122+
done
123+
else
124+
echo "Retry cleanup: no matching stacks found"
125+
fi
126+
fi
80127
sleep $DELAY
81128
ATTEMPT=$((ATTEMPT + 1))
82129
DELAY=$((DELAY * 2)) # Exponential backoff

.github/workflows/pr.yaml

Lines changed: 206 additions & 57 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 153 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,99 @@
11
# ziti-k8s-agent
22

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.
44

5-
## Namespace
5+
## Installation
66

7-
A namespace will not be created. The agent may be installed in any existing namespace.
7+
### Prerequisites
88

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+
```
1020

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)
1222

13-
### Select by Namespace
23+
> **⚠️ SECURITY WARNING**: This webhook requires a Ziti admin identity with full network privileges. Handle with extreme care!
1424
15-
Select all pods in namespaces labeled `tunnel.openziti.io/enabled="true"`.
25+
Create a secret containing your complete Ziti identity JSON configuration:
1626

1727
```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)"
1948
```
2049

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)
2253

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+
```
2465

2566
### Select by Pod
2667

27-
Select pods labeled `tunnel.openziti.io/enabled="true"` in any namespace.
68+
Select pods labeled `tunnel.openziti.io/enabled="true"` in any namespace:
2869

2970
```bash
71+
# Label deployment for sidecar injection
3072
kubectl patch deployment/{name} -p '{"spec":{"template":{"metadata":{"labels":{"tunnel.openziti.io/enabled":"true"}}}}}'
31-
```
3273
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+
```
3479

3580
### Select by Namespace and Pod
3681

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"`:
4083

4184
```bash
85+
# Label both namespace and deployment
4286
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"
4393
```
4494

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+
4597
## Specify Ziti roles for Pod Identities
4698

4799
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
70122
71123
### Prerequisities
72124
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
74126
1. A JSON identity configuration file for an OpenZiti identity with the admin privilege
75127
1. A K8S namespace in which to deploy the agent
76128
77-
### Set Optional Environment Variables
129+
## Advanced Configuration
78130
79-
These optional variables will override defaults.
131+
### Custom Values File
80132
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"
107185
```
108186
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
110188
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+
```
112204
113-
Required environment variables:
205+
### DNS Search Domains
114206
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:
117208

118209
```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}"
120213
```
121214

122-
### Apply the Manifest
215+
### Resource Management
216+
217+
Configure resource requests and limits for production deployments:
123218

124219
```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"
126226
```

charts/ziti-webhook/Chart.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
apiVersion: v2
2+
name: ziti-webhook
3+
description: A Helm chart for Ziti Kubernetes Admission Webhook
4+
type: application
5+
version: 0.1.0
6+
appVersion: "latest"
7+
keywords:
8+
- ziti
9+
- openziti
10+
- zero-trust
11+
- networking
12+
- kubernetes
13+
- admission-webhook
14+
home: https://netfoundry.io/docs/openziti/
15+
sources:
16+
- https://github.com/netfoundry/ziti-k8s-agent
17+
maintainers:
18+
- name: OpenZiti Team
19+

0 commit comments

Comments
 (0)