Skip to content
Merged
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
5 changes: 4 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,12 @@ jobs:
- name: Render AWS GPU SQS example
run: helm template render-worker charts/render-worker -f examples/values-aws-gpu-sqs.yaml > /tmp/rendered/aws-gpu-sqs.yaml

- name: Render security hardening example
run: helm template render-worker charts/render-worker -f examples/values-security-hardening.yaml > /tmp/rendered/security-hardening.yaml

- name: Validate rendered Kubernetes manifests
run: |
for manifest in /tmp/rendered/default.yaml /tmp/rendered/local.yaml /tmp/rendered/local-minio.yaml /tmp/rendered/aws-gpu-sqs.yaml; do
for manifest in /tmp/rendered/default.yaml /tmp/rendered/local.yaml /tmp/rendered/local-minio.yaml /tmp/rendered/aws-gpu-sqs.yaml /tmp/rendered/security-hardening.yaml; do
echo "Validating ${manifest}"
kubeconform -strict -summary \
-kubernetes-version "${KUBE_VERSION}" \
Expand Down
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: lint template template-local template-minio smoke-local test
.PHONY: lint template template-local template-minio template-security smoke-local test

lint:
helm lint charts/render-worker
Expand All @@ -12,6 +12,9 @@ template-local:
template-minio:
helm template render-worker charts/render-worker -f examples/values-local-minio.yaml

template-security:
helm template render-worker charts/render-worker -f examples/values-security-hardening.yaml

smoke-local:
scripts/smoke-local.sh

Expand Down
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ This repository packages the public-safe Kubernetes layer around a render farm:
[Local Development](#local-development) |
[Architecture](#architecture) |
[Scheduling](#scheduling) |
[Security](#security) |
[Repository Map](#repository-map) |
[Roadmap](#roadmap) |
[Contributing](#contributing) |
Expand Down Expand Up @@ -134,14 +135,24 @@ belongs to the application or platform chart that renders API pods.
Read `docs/scheduling.md` for Karpenter/EKS Auto Mode integration notes and the
GPU/CPU scheduling profiles used by `examples/values-aws-gpu-sqs.yaml`.

## Security

Use workload identity and externally managed secrets for private deployments.
The public examples use placeholder account ids and never include AWS keys,
renderer licenses, customer scenes, or production values.

Read `docs/security.md` for IRSA/EKS Pod Identity guidance, secret handling
boundaries, and the opt-in NetworkPolicy profile in
`examples/values-security-hardening.yaml`.

## Repository Map

```text
charts/render-worker/ Helm chart, templates, values, and schema
examples/ Public-safe local and AWS-style values files
workers/mock-render-worker/ Local mock worker used by smoke tests
scripts/ Contract, render, and smoke validation scripts
docs/ Architecture, scheduling, development, roadmap, and evidence map
docs/ Architecture, scheduling, security, development, roadmap, and evidence map
.github/ CI workflow and issue/PR templates
VISION.md Product direction and safety boundary
```
Expand Down
24 changes: 24 additions & 0 deletions charts/render-worker/templates/networkpolicy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{{- if .Values.networkPolicy.enabled }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: {{ default (printf "%s-network" (include "render-worker.fullname" .)) .Values.networkPolicy.name }}
namespace: {{ .Values.namespace.name }}
labels:
{{- include "render-worker.labels" . | nindent 4 }}
spec:
podSelector:
matchLabels:
{{- include "render-worker.selectorLabels" . | nindent 6 }}
workload.renderfarm.dev/type: worker
policyTypes:
{{- toYaml .Values.networkPolicy.policyTypes | nindent 4 }}
{{- with .Values.networkPolicy.ingress }}
ingress:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.networkPolicy.egress }}
egress:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}
31 changes: 31 additions & 0 deletions charts/render-worker/values.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,37 @@
"affinity": {
"type": "object"
},
"networkPolicy": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean"
},
"name": {
"type": "string"
},
"policyTypes": {
"type": "array",
"items": {
"type": "string",
"enum": ["Ingress", "Egress"]
},
"minItems": 1
},
"ingress": {
"type": "array",
"items": {
"type": "object"
}
},
"egress": {
"type": "array",
"items": {
"type": "object"
}
}
}
},
"adapters": {
"type": "object",
"properties": {
Expand Down
9 changes: 9 additions & 0 deletions charts/render-worker/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,15 @@ nodeSelector: {}
tolerations: []
affinity: {}

networkPolicy:
enabled: false
name: ""
policyTypes:
- Ingress
- Egress
ingress: []
egress: []

keda:
enabled: false
minReplicaCount: 0
Expand Down
2 changes: 2 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ It owns reusable Kubernetes primitives:
- Node scheduling controls for GPU workers and CPU postprocess jobs.
- ServiceAccount configuration for AWS permissions.
- ConfigMap and Secret injection points.
- Opt-in NetworkPolicy for worker network boundaries.
- Post-processing `Job` template.

## Adapter Seams
Expand Down Expand Up @@ -50,6 +51,7 @@ The adapter values are chart contracts only. They do not create SQS queues, buck
- KEDA owns runtime worker replica count when autoscaling is enabled. The chart omits `Deployment.spec.replicas` in that mode so Helm upgrades do not reset an active worker pool.
- KEDA scaler authentication is modeled separately from worker AWS access. The worker ServiceAccount handles job execution permissions; `TriggerAuthentication` handles scaler access to queue metrics.
- GPU render workers, CPU postprocess jobs, and API-facing pods should use separate node pools. API pods are outside this chart and should be scheduled by the application or platform chart that owns them.
- AWS permissions should use workload identity, not committed keys. Renderer licenses and customer credentials should be supplied by private secret management systems, not public values files.
- `worker.env` remains a compatibility overlay and can override adapter-generated environment variables when a private deployment needs a custom contract.
- S3/SQS/EKS names in examples are placeholders. Production infrastructure, IAM policies, and cloud resources are expected to live in private environment repositories.
- Post-processing is currently represented as a chart-rendered `Job`; its production upgrade semantics are tracked separately because Kubernetes Job pod templates are immutable after creation.
Expand Down
30 changes: 23 additions & 7 deletions docs/delivery-prompts.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,18 +107,34 @@ Validation:
Repository: RayLi-Muye/renderfarm-k8s-toolkit
Issue: #5 Add security hardening examples for AWS permissions and secrets

Add public-safe security examples for AWS permissions, secrets, and network isolation.
This node has been implemented with public-safe security examples for AWS
permissions, secrets, and network isolation.

Expected files:
- examples/*
- charts/render-worker/templates/*
Implemented files:
- examples/values-security-hardening.yaml
- charts/render-worker/values.yaml
- charts/render-worker/values.schema.json
- charts/render-worker/templates/networkpolicy.yaml
- docs/security.md
- README.md
- docs/architecture.md
- docs/evidence-map.md
- docs/development.md
- scripts/chart-contract-tests.sh
- scripts/render-examples.sh
- .github/workflows/ci.yml
- Makefile

Validation:
- Helm lint and template rendering pass.
- Security examples use placeholders only.
- Docs explain where production IAM, Secrets Manager, External Secrets, and NetworkPolicy decisions live.
- `make template-security` renders the security hardening profile.
- `make test` checks placeholder IRSA, NetworkPolicy selection, egress gateway
placeholder, and absence of static AWS key env or generated Secrets.
- `scripts/render-examples.sh` validates the security example with kubeconform
when available.

Follow-up direction:
- Add pod/container securityContext fields only if a concrete private runtime
contract needs them and they can remain backward-compatible.
```

## Node: GPU Scheduling And Karpenter Examples
Expand Down
3 changes: 2 additions & 1 deletion docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ make lint
make template
make template-local
make template-minio
make template-security
make smoke-local
make test
```

`scripts/render-examples.sh` also validates rendered manifests with kubeconform when it is installed locally. CI installs Helm and kubeconform with pinned versions and SHA256 checksums, then validates built-in Kubernetes resources and KEDA CRDs through a pinned CRD schema catalog.
`scripts/render-examples.sh` also validates default, local, local MinIO, AWS GPU/SQS, and security-hardening rendered manifests with kubeconform when it is installed locally. CI installs Helm and kubeconform with pinned versions and SHA256 checksums, then validates built-in Kubernetes resources and KEDA CRDs through a pinned CRD schema catalog.

`make smoke-local` runs the public mock worker path from `workers/mock-render-worker/mock-render-worker.sh`. It consumes `examples/mock-queue.txt`, writes placeholder frame output, and creates a postprocess manifest without AWS credentials, a real renderer, or a Kubernetes cluster.

Expand Down
4 changes: 3 additions & 1 deletion docs/evidence-map.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ This file maps resume claims to public repository evidence.
| KEDA scaler authentication | `charts/render-worker/templates/keda-triggerauthentication.yaml`, `examples/values-aws-gpu-sqs.yaml` | Render the AWS example and inspect `TriggerAuthentication` plus `authenticationRef` | Implemented | Cluster-level KEDA operator identity is configured outside this chart |
| S3 asset and output workflow | `worker.env.ASSET_BUCKET`, `worker.env.OUTPUT_BUCKET`, `examples/values-aws-gpu-sqs.yaml` | Render examples and inspect worker environment variables | Implemented | No bucket or object storage is created |
| Queue, storage, and identity adapter seams | `charts/render-worker/values.yaml`, `charts/render-worker/templates/_helpers.tpl`, `examples/values-local.yaml`, `examples/values-local-minio.yaml`, `examples/values-aws-gpu-sqs.yaml` | Run `make test`; inspect adapter-generated worker env, KEDA SQS metadata, ServiceAccount annotations, podIdentity provider rendering, and existingSecret envFrom | Implemented | Adapter values are chart contracts only; they do not create queues, buckets, IAM roles, Secrets, MinIO, or AWS resources |
| Secure AWS access pattern | `charts/render-worker/templates/serviceaccount.yaml`, `charts/render-worker/templates/keda-triggerauthentication.yaml` | Inspect ServiceAccount annotations and KEDA pod identity settings | Started | Least-privilege IAM policies remain environment-specific |
| Secure AWS access pattern | `charts/render-worker/templates/serviceaccount.yaml`, `charts/render-worker/templates/keda-triggerauthentication.yaml`, `examples/values-security-hardening.yaml`, `docs/security.md` | Run `make test`; inspect placeholder ServiceAccount annotations, KEDA pod identity settings, and secret guidance | Implemented | Least-privilege IAM policies, role bindings, and secret backends remain environment-specific |
| Config and secret management | `charts/render-worker/templates/configmap.yaml`, `charts/render-worker/templates/secret.yaml` | Render values with string-like and numeric values; output remains string typed | Implemented | Secrets are injection points, not a production secret manager |
| NetworkPolicy worker boundary | `charts/render-worker/templates/networkpolicy.yaml`, `examples/values-security-hardening.yaml`, `docs/security.md` | Run `make template-security` or `make test`; inspect worker-only pod selector, empty ingress, DNS egress, and placeholder egress gateway | Implemented | Does not create CNI policy enforcement, VPC endpoints, security groups, NAT gateways, or firewall rules |
| Post-render batch processing | `charts/render-worker/templates/postprocess-job.yaml` | Render local or AWS examples and inspect the `Job` | Implemented | Upgrade semantics need hardening before production use |
| Public mock worker smoke path | `workers/mock-render-worker/mock-render-worker.sh`, `scripts/smoke-local.sh`, `examples/mock-queue.txt` | Run `make smoke-local` and inspect placeholder frame output plus the postprocess manifest | Implemented | Mock path validates the public worker contract only; it is not a real renderer, queue service, object store, or cluster test |
| Chart contract tests and values schema | `scripts/chart-contract-tests.sh`, `charts/render-worker/values.schema.json` | Run `make test`; CI also runs these tests on PRs and `main` pushes | Implemented | Contract tests inspect rendered manifests and schema failures only; no live Kubernetes, KEDA operator, AWS SQS, MinIO, or GPU node behavior is exercised |
Expand All @@ -28,4 +29,5 @@ This repository supports claims about reusable Kubernetes orchestration patterns
- The mock worker is a public-safe contract test and does not contain renderer binaries, licenses, customer scenes, or cloud credentials.
- AWS examples use placeholder account IDs and resource names.
- Scheduling examples use placeholder labels and taints. Private cluster infrastructure owns the actual Karpenter, EKS Auto Mode, or managed node group configuration.
- Security examples use placeholder IAM role ARNs, placeholder egress labels, and no static AWS keys or renderer license material.
- Claims should be read as evidence of orchestration, packaging, and review discipline, not as proof of a deployed customer environment.
96 changes: 96 additions & 0 deletions docs/security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Security Hardening

This repository contains public-safe chart contracts and examples only. It does
not contain AWS credentials, renderer licenses, customer scene files, production
bucket names, production queue names, or private account identifiers.

## AWS Permissions

Do not commit AWS access keys, static session tokens, or `.env` files. Render
workers should receive AWS permissions through the Kubernetes ServiceAccount
identity path used by the cluster:

- **IRSA**: annotate the worker ServiceAccount with a role ARN. The public
examples use placeholder account ids and role names.
- **EKS Pod Identity**: bind the ServiceAccount to a role outside this chart and
configure KEDA's `TriggerAuthentication` provider.
- **Existing Secret**: use only for local/private integrations where a secret is
created by an external controller. Do not publish the secret contents.

The chart can render a ServiceAccount annotation for IRSA:

```yaml
adapters:
identity:
type: irsa
irsa:
annotationKey: eks.amazonaws.com/role-arn
roleArn: arn:aws:iam::000000000000:role/render-worker-irsa
```

The IAM role and policy are owned by private infrastructure. A typical
least-privilege policy should be scoped to the exact queue, buckets, KMS keys,
and logs used by the environment. Keep the actual policy document in the private
infrastructure repository, not in public example values.

## Secret Handling

Do not put these values in `worker.env`, `secret.stringData`, examples, issues,
PR descriptions, or logs:

- AWS access keys or session tokens;
- V-Ray, Arnold, RenderMan, Blender add-on, or DCC license files;
- customer scenes, paths, frame output, or asset URLs;
- production queue URLs, bucket names, ECR repositories, or account ids.

Use one of these private patterns instead:

- AWS Secrets Manager plus External Secrets Operator;
- another cluster-approved external secret controller;
- sealed/encrypted secrets stored in a private repo;
- short-lived identity from IRSA or EKS Pod Identity whenever possible.

`secret.create` is intentionally `false` in the security example. If a private
deployment needs a Kubernetes Secret, create it outside this public chart and
reference it with the `existingSecret` identity adapter.

## Network Boundary

Render workers are queue consumers. They normally do not need inbound traffic
from API pods, submitters, CI jobs, or unrelated workloads. Enable
`networkPolicy` when the target cluster enforces Kubernetes NetworkPolicy:

```yaml
networkPolicy:
enabled: true
policyTypes:
- Ingress
- Egress
ingress: []
egress:
- to:
- podSelector:
matchLabels:
renderfarm.dev/network-role: aws-egress-gateway
ports:
- protocol: TCP
port: 443
```

The example in `examples/values-security-hardening.yaml` also allows DNS egress.
Adapt labels and egress paths for the private cluster. Kubernetes NetworkPolicy
does not create VPC endpoints, security groups, NAT gateways, or firewall rules.

## Public Example Boundary

`examples/values-security-hardening.yaml` demonstrates:

- ServiceAccount annotation shape with placeholder IRSA role ARN;
- no direct AWS key injection;
- no renderer license or customer secret material;
- opt-in NetworkPolicy that selects only worker pods;
- egress through DNS and a placeholder private AWS egress gateway.

It is a review artifact, not a production values file. Private environments must
replace placeholder names, own IAM and secret manager resources, and validate the
network policy against their cluster CNI and egress design.
Loading