Kubernetes Agent, GitOps Workflows, Cluster Access, Environments, and Deployment Integration: Guided Hands-On Workflow and Core Operations
Work through a Free-compatible fixture lab for agent configuration, authorization, least-privilege Kubernetes access, environment evidence, and safe cleanup, with an optional disposable local-cluster extension.
Learning objectives
- Create a disposable Free-compatible fixture that models agent registration, CI authorization, RBAC, Flux reconciliation, and environment evidence.
- Predict which project/environment may use an agent and which Kubernetes operations should be allowed or denied.
- Inspect sanitized agent/API evidence without exposing agent tokens or kubeconfig contents.
- Optionally exercise the trust path on a local disposable Kubernetes cluster.
- Remove temporary agent/cluster resources and prove no residual access remains.
gitops.manifest_projects functionality was removed in
GitLab 17.0; current GitOps guidance uses
Flux plus the GitLab Agent. Therefore the mandatory
chapter path is manifest/identity simulation with no real cluster or
paid feature; any live cluster exercise is optional and disposable.
1. Preflight: mandatory path needs no Kubernetes cluster
Create a local repository named gitlab-ch28-agent-lab.
The required path uses YAML/JSON fixtures and local validation only.
It does not create a GitLab agent, cloud cluster, runner, token, or
real environment. If you already have a disposable GitLab project
and a local kind, k3d, or similar cluster,
the optional extension shows how to test the same authorization
model safely.
mkdir gitlab-ch28-agent-lab && cd gitlab-ch28-agent-lab
git init && git switch -c main
mkdir -p .gitlab/agents/lab-agent fixtures manifests evidence
printf 'chapter-28 training only
' > README.md
2. Predict the trust path before writing YAML
Write these predictions in evidence/predictions.md:
-
Only jobs from
training/platform/appwhose GitLab environment isstagingorreview/*should be candidates for agent access. -
A read-only Kubernetes identity should be able to list Pods in
ch28-laband be denied namespace deletion. - A GitLab environment record and a Kubernetes workload must be verified separately.
- A Flux reconciliation revision must match the desired manifest revision before calling the GitOps path converged.
3. Model the agent configuration and authorization
Create the exact configuration path that a real agent uses:
# .gitlab/agents/lab-agent/config.yaml
ci_access:
projects:
- id: training/platform/app
environments:
- review/*
- staging
# Premium/Ultimate optional hardening:
# access_as:
# ci_job: {}
On Free this models project/environment authorization. The commented impersonation block is Premium/Ultimate and should remain disabled in the mandatory lab. Note the trust boundary: this file belongs to the agent configuration project; a broad group authorization would implicitly extend access to descendant projects and deserves stricter review.
4. Model least-privilege Kubernetes RBAC
Create fixtures/rbac.yaml from the following fixture:
apiVersion: v1
kind: Namespace
metadata:
name: ch28-lab
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: workload-reader
namespace: ch28-lab
rules:
- apiGroups: [""]
resources: ["pods", "configmaps"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: workload-reader-binding
namespace: ch28-lab
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: workload-reader
subjects:
- kind: Group
name: gitlab:ci_job
apiGroup: rbac.authorization.k8s.io
The fixture intentionally grants only get/list
for Pods and ConfigMaps in one namespace. The subject
gitlab:ci_job only becomes meaningful when
Premium/Ultimate CI job impersonation is actually enabled. On the
Free simulation, treat it as the desired production RBAC contract
rather than an active identity.
5. Model a read-only CI job and its denial
Create fixtures/ci-job.yml:
cluster_read:
stage: verify
environment:
name: staging
script:
- kubectl config use-context "$AGENT_CONTEXT"
- kubectl auth can-i get pods -n ch28-lab
- kubectl get pods -n ch28-lab -o name
- kubectl auth can-i delete namespaces
The optional live extension assumes a disposable runner/toolchain
that already provides a reviewed, pinned
kubectl version compatible with the cluster; the
fixture deliberately does not pull a mutable
latest image. The first two commands are expected to
succeed only if the selected context exists and Kubernetes RBAC
allows them. The final
kubectl auth can-i delete namespaces should print
no under the intended least-privilege model. Do not
replace auth can-i with an actual namespace delete
merely to prove denial.
6. Model current GitOps with Flux
Create fixtures/flux.yaml:
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: ch28-manifests
namespace: flux-system
spec:
interval: 5m
url: https://gitlab.example.invalid/training/platform/manifests.git
ref:
branch: main
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: ch28-staging
namespace: flux-system
spec:
interval: 5m
path: ./clusters/staging
prune: true
sourceRef:
kind: GitRepository
name: ch28-manifests
The URL is intentionally non-routable. This fixture teaches the object relationships without contacting any real service. Current GitLab guidance recommends Flux for pull-based GitOps; the GitLab Agent is complementary rather than the reconciler itself.
7. Validate the fixtures locally and preserve provenance
python - <<'PY'
from pathlib import Path
for p in [
Path('.gitlab/agents/lab-agent/config.yaml'),
Path('fixtures/rbac.yaml'), Path('fixtures/ci-job.yml'), Path('fixtures/flux.yaml')
]:
assert p.exists() and p.stat().st_size > 0, p
text=Path('.gitlab/agents/lab-agent/config.yaml').read_text()
assert 'environments:' in text and 'staging' in text
assert 'access_as:' not in '
'.join(line for line in text.splitlines() if not line.lstrip().startswith('#'))
print('fixture structure: PASS')
PY
git add . && git commit -m "Add Chapter 28 Kubernetes trust fixtures"
git rev-parse HEAD
sha256sum .gitlab/agents/lab-agent/config.yaml fixtures/rbac.yaml fixtures/flux.yaml
The Git commit SHA and file hashes make the lab reproducible. They are evidence about configuration identity, not evidence that any cluster accepted the configuration.
8. Optional disposable live extension
Only if you already have a disposable GitLab project and a local cluster:
- Create/register a uniquely named agent in the disposable project. Creating an agent/token requires Maintainer/Owner.
- Create one token, store it only in the installation mechanism, and never echo it. An agent can have at most two active tokens.
- Install agentk with the current supported Helm/glab workflow into the local cluster.
-
Apply a dedicated
ch28-labnamespace and minimal RBAC. - Authorize only the disposable project/environment. Wait for authorization propagation.
-
Run a tiny read-only job or local access test and record only
resource names,
auth can-iresults, agent ID, job ID, and commit SHA. - Revoke the agent token, delete the GitLab agent registration, uninstall agentk, and remove the namespace. Deleting the GitLab agent does not remove cluster-side resources automatically.
9. Correlate GitLab environment and cluster identity
Use a sanitized evidence record rather than copying full kubeconfig or Pod environment variables:
{
"gitlab": {
"project": "training/platform/app",
"commit_sha": "0123456789abcdef...",
"pipeline_id": 4201,
"job_id": 4207,
"environment": "staging",
"agent": "training/platform/agent-config:lab-agent"
},
"kubernetes": {
"namespace": "ch28-lab",
"workload": "deployment/ch28-demo",
"image_digest": "sha256:111111...",
"observed_generation": 3
},
"gitops": {
"controller": "Flux",
"desired_revision": "main@sha1:012345...",
"ready": true
}
}
The point is causality: source/ref, pipeline/job, environment, image digest, controller revision, and observed workload must align. A UI badge alone is not sufficient.
10. Control-selection challenge
Choose the smallest correct control for each requirement:
| Requirement | Best surface |
|---|---|
| Allow only staging/review jobs in one project to obtain agent context | ci_access.projects[].environments |
| Give each CI job a Kubernetes-native identity for RBAC |
Premium/Ultimate access_as: ci_job + Kubernetes
RBAC
|
| Continuously reconcile desired manifests without pipeline push access | Flux pull-based GitOps |
| Prove a job may list Pods but cannot delete namespaces |
kubectl auth can-i with the effective context
|
11. Cleanup and verification
For the mandatory local fixture, keep sanitized evidence only if useful, then delete the disposable directory from its parent. For an optional live exercise, cleanup order matters: revoke/rotate credentials first if compromised; otherwise revoke the lab token, remove the GitLab agent registration, uninstall agentk/Flux resources that were created only for the lab, delete the lab namespace, and verify each resource is gone. Do not infer that deleting the agent in GitLab cleaned the cluster.
Knowledge check
Why is the mandatory path fixture-based?
It keeps the chapter Free-compatible and prevents learners from needing a cloud/Kubernetes cluster while still teaching the real identity and authorization model.
Why use kubectl auth can-i instead of deliberately deleting a protected object?
It proves authorization behavior without risking a destructive cluster mutation.
If you delete the GitLab agent registration, is agentk automatically removed from Kubernetes?
No. GitLab explicitly requires cluster-side cleanup separately.
What current controller performs GitOps reconciliation in this chapter?
Flux. The GitLab Agent supports connection/access/visibility but its legacy built-in pull-based GitOps was removed.
What should be stored as lab evidence?
Sanitized IDs, SHAs, digests, resource names, authorization results, and controller revisions—not tokens, kubeconfig contents, or broad environment dumps.
12. Summary and next bridge
You have now modeled the entire trust path without requiring a live cluster. Lesson 3 turns those mechanics into architecture choices: push versus pull, broad versus narrow authorization, and shared versus isolated cluster designs.
Primary sources and version notes
These lessons were finalized against current official GitLab documentation on 2026-08-22. Kubernetes, Flux, agentk, glab, KAS, and cluster security evolve independently, so re-check current GitLab version/tier, supported agent/Kubernetes versions, CLI syntax, and cluster policy before production use.
- GitLab 19.3 release
- Connecting a Kubernetes cluster with GitLab
- Install the GitLab Agent for Kubernetes
- Using GitLab CI/CD with a Kubernetes cluster
- Grant users Kubernetes access
- Using GitOps with a Kubernetes cluster
- Migrate legacy agent GitOps to Flux
- Managing agent instances and tokens
- Kubernetes Agent REST API
- Kubernetes managed resources and environments
- GitLab deprecations and removals
- GitLab token security overview
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.