
IT governance: who gets in, who can deploy, and how you prove it
A control question for any company with its own technical team: if someone leaves tomorrow, how many different places do you have to touch to revoke their access? If the answer is "we'd have to check", you don't have a security problem yet. You have a governance problem, which is the one causing it.
The scene is a familiar one. Every service with its own login: the repository, the cloud console, the issue tracker, the staging database someone opened "just for a bit". Permissions are requested over WhatsApp and granted on trust. Production access is kept by whoever once asked for it, including the intern who joined in the summer and is still in the group. And when something breaks, "who changed this and when?" gets answered by reconstructing three people's memories.
None of that gets fixed with a committee or a policy document nobody reads.
Where it hurts, in money
The cost doesn't show up on an invoice; it shows up in four places.
Onboarding and offboarding. Bringing someone on means six emails and two days of waiting; removing them is a list nobody maintains. The day there's a contentious departure, the company finds out how many services they were still inside.
The audit. A large client, or a certification, comes along and asks for something very specific: the list of who has access to production data and the evidence that this access is controlled. If that list has to be assembled by hand, the answer arrives late and full of holes. And that's where deals that were already closed get stuck.
Turnover. When the knowledge of who can do what lives in the head of the person who set the system up, their departure doesn't take an employee: it takes the map.
Incidents. Without traceability there is no root cause, only hypotheses. And an incident that can't be explained repeats itself.
IT governance is not a committee or a document. It's three concrete things: centralized identity, permissions derived from a single place, and a path to production nobody can bypass.
Three layers, not ten policies
One identity, one login
People exist in a single place and services delegate to it. Onboarding and offboarding happen once.
Permissions that are derived, not copied
The role is declared where identity lives and travels in the token. The application reads it and decides, with no parallel list.
A single path to production
The repository is the truth, and anything changed by hand reverts itself. A change in production is a commit with an author.
Identity first, because everything else hangs from it
At Zetesis we always start here, and not out of architectural taste: as long as every service keeps its own user registry, any access policy is a promise.
The piece is Keycloak speaking OIDC. A single identity issuer, with the applications as consumers. We run ours as an independent service, with its own image, its own Helm chart and its own release cycle: Keycloak published on a single domain, from which the platform's applications hang. Those applications know nothing about passwords; they speak OIDC with the authorization code flow and PKCE, and the token exchange never leaves the cluster.
What matters for governance is not the product, it's that the realm is declared as code. The configuration —clients, roles, organizations, policies— is 2,200 lines of JSON in a repository, applied by keycloak-config-cli on every sync, with non-destructive import so a deployment doesn't delete what isn't declared. Changing who can do what stops being five clicks in an admin console nobody remembers making.
And from that comes the part that's hardest to explain and most noticeable: permissions are derived, not replicated. In our platform there are four roles with business meaning on the identity side —global administration, organization administration and two product capabilities—. When someone signs in, the application reads those roles and their organization membership directly from the token and translates them into per-tenant internal permissions. The translation happens on every sign-in, so identity commands and the application obeys; there aren't two permission lists someone has to reconcile by hand.
That has a practical consequence that usually convinces more than theory. The API tokens a user creates for integrations are stored only as a SHA-256 hash —the cleartext value is shown once and never persisted—, are bound to a specific tenant and are immutable after creation. And on every request it checks again that the person behind the token still has the required role. If their permission is revoked in identity, the token stops working instantly even though it still exists. Revoking in one place truly revokes.
Change is governed in the repository
The second uncomfortable question is who can deploy what. The usual answer —"those who have the credentials"— is not an answer.
Our infrastructure lives declared in a GitOps repository: three Kubernetes clusters on Talos, with ArgoCD reconciling the declared state against what's running —the whole setup is described in the homelab Kubernetes and GitOps post—. The discipline is in two unglamorous details. The first: every single application has automated reconciliation with selfHeal and prune, without a single exception. If someone comes in through the back door and changes something with kubectl, ArgoCD undoes it. There's no shortcut to production; there's a single door.
The second: ArgoCD's default project is deliberately disabled —no source repositories, no destinations and every resource blacklisted—, and access control starts with no default permissions. Each application has to declare a custom project with its allowed repositories and namespaces. It's the opposite of the usual pattern, where everything fits in "default" and nobody knows what can touch what.
With that, a production deployment is a one-line change, with an author, a date and a reason:
$ git log --oneline -2 -- px-platon/alejandro/envs/prod/env.json
ec688cc Merge pull request #239 from Zetesis-Labs/auto-bump/zetesis-portal-30641883917
c562212 chore(prod): bump ZetesisPortal images and chart
$ git show c562212 -- px-platon/alejandro/envs/prod/env.json
- "webImageTag": "v0.8.23",
+ "webImageTag": "v0.8.24",
That commit is written by a bot: when a version is released, the pipeline opens a pull request in the infrastructure repository with the new image tag. A person merges it. That way, promotion to production stays separate from development, is reviewable before it happens and auditable afterwards.
CI/CD as a way of governing teams
The third layer is what turns everything above into something a development team can use without friction.
Nobody needs production to test. Every labeled pull request spins up its own complete environment: an isolated namespace, its own database, its own domain and even its own identity instance. When the PR closes it destroys itself, and periodic tasks sweep up whatever survives —orphaned databases, old registry images—. When testing is free, production access stops being a daily need and becomes an exception.
Secrets never touch the repository. There is a single source —a self-hosted secrets manager— and the External Secrets operator materializes them in each environment; the Helm chart won't even render unless you tell it which secret to read from. Encryption in git only for the bare minimum needed to bootstrap the cluster before that operator exists. And a secrets scanner runs on every push and every pull request, across the full history. The three layers and how they fit together are broken down in the homelab security and operations post.
The rules are verified by a machine, not a meeting. CI validation renders all the manifests and validates them against the schema, and it also checks three policies written as executable code: no wildcards allowed in chart versions, mandatory failure when a template variable is missing, no use of ArgoCD's default project. A policy that can't be verified automatically isn't a policy: it's an intention.
Why analysis comes before the tool
A warning, because it's the most expensive mistake we see.
Recently Singular Solving was working with an education group that wanted to build its systems following a recognized sector reference framework, and we did that analysis. Looking at it closely surfaced the interesting part: the framework describes hundreds of business and application capabilities, and names digital identity among them, but it's purely descriptive. It says nothing about how to solve it. The school had email with one provider, its classroom platform with another, communications with a third, each with its own username and password. The problem wasn't a lack of applications: it was fragmentation. And no capability catalog tells you who should access what.
It's worth saying precisely: there, an identity server with Keycloak was proposed scope, not an implementation we carried out. What was delivered was the analysis.
That's why our work starts with an inventory of real access, not with installing anything. Who gets in, where, with what permission and who granted it. The tool comes later, once you know what you're governing.
Who it's for
It fits if your internal systems are used by dozens of people and onboarding a new employee is still a manual task list. If a client or a certification has asked you for evidence of access control and you assembled it by hand. If more than one person can deploy to production and there's no record of who did it. If you've inherited a platform and don't know who has access to what.
It doesn't fit if your team is three people sitting together: the governance you need there is an honest spreadsheet, not an identity server. Nor if you want the certificate without changing how you work —we can help you document what's there, but not make it look like something else—. And nor if you expect to outsource operations forever: we build the system so your team can run it.
If what hurts isn't who deploys but that deploying is scary —slow pipelines, untested backups, secrets in a spreadsheet—, that's the other service: DevOps and infrastructure consulting. They're siblings and often hired together, but they answer different questions.
Questions we always get
Isn't this just setting up a Keycloak?+
Keycloak installs in an afternoon; that's not where the work is. It's in deciding the model: what's a role and what's a capability, how the organization's structure is represented, which applications delegate and in what order. A badly modeled identity server adds a layer to the problem instead of solving it.
What does the business gain from a single identity issuer?+
Three verifiable things. People are onboarded and offboarded once, not once per service. Roles aren't replicated in every application: they're declared where identity lives, travel in the token, and the application translates them on every sign-in. And revoking truly revokes: if you remove a role, the API tokens that depended on it stop working on the next request even though they still exist.
Does everything have to be migrated at once?+
No. You start with the applications where access is most sensitive and move one by one: every application that delegates is one fewer user list to maintain. Whatever can't be moved gets documented as an explicit exception, which is already better than ambiguity.
We don't use Kubernetes. Is half of it still useful to us?+
The identity layer is independent of where your things run. Change governance only needs the infrastructure to be described as configuration, with or without Kubernetes; what doesn't work is governing hand-configured servers.
Related consulting

Building a homelab from scratch: Kubernetes and GitOps - Homelab (03/06)

Building a homelab from scratch: security and operations - Homelab (04/06)

DevOps and infrastructure consulting

One deployment per customer or one space per customer

From standard to graph to project

Platform architecture consulting
Let's talk
Tell us how many different places you have to touch to offboard someone at your company. With that answer we can already tell you where we'd start.