Access control
Design who can access Lamassu through principals, policies, resource permissions and HTTP route authorization.
Lamassu access control turns an authenticated identity into concrete permissions. The OIDC provider or the client certificate proves who makes a request; the authz service decides what that identity can do and over which resources.
Lamassu does not assign permissions directly to users. The full chain is:
credential → matching principal → granted policies → rules → decisionThis model lets you represent people, identity-provider groups, service accounts and devices without coupling authorization to a specific provider.
Essential concepts
A principal connects a credential to Lamassu. It defines how to recognize an OIDC or X.509 identity and can be active or disabled.
A policy groups reusable permissions. It can be granted to several principals and can contain rules about Lamassu entities, rules about HTTP routes or both.
An entity rule grants actions over resources such as certification authorities, certificates, issuance profiles, devices, DMSs, keys or alert subscriptions. It can cover all resources of a type or be limited by identifier, relation or attribute.
An HTTP rule grants actions associated with API routes. It is the mechanism the Gateway uses to decide whether a request may cross the perimeter.
A grant is the association between a principal and a policy. Removing the grant removes all permissions contributed by that policy, without modifying it for other principals.
Authentication and authorization are distinct controls
A valid JWT or a valid client certificate does not grant access by itself. The credential must match at least one active principal and one of its policies must allow the requested operation.
Two decision systems
Lamassu uses two authorization paths depending on who implements the protected service. They share principals, policies and grants, but they do not interpret the rules the same way.
Integrated or external HTTP services → Gateway → HTTP rules
Services developed by Lamassu → service middleware → entity rulesThe difference lies in the integration point
An external service can be protected without knowing Lamassu's internal authorization model. A service developed by Lamassu embeds the authorization engine and can decide on concrete resources and filter its queries.
Integrated or external HTTP services
This path protects APIs that join the platform through the Gateway but do not natively implement Lamassu's authorization SDK. Job Manager is the current example. The same pattern allows integrating other HTTP services as long as their routes are described in an authz HTTP schema.
The decision is made before forwarding the request to the service:
- Envoy Gateway authenticates the request, usually validating a JWT against the OIDC provider's JWKS.
- For a protected route, Envoy sends the method, URL, headers and required data to
/v1/ext_authz/check. authzextracts the credential and resolves all active principals matching it.- It separately loads the policies granted to each principal.
- The HTTP schema translates the method and route combination into a logical action, such as
nbi-job-readornbi-workflow-create. authzlooks for an HTTP rule granting that action.- If the route declares constraints, it compares request data with the normalized attributes of the same principal contributing the policy.
- A satisfying result lets Envoy forward the request; any other response blocks it at the Gateway.
When it allows access, authz returns the selected principal in x-current-user. The Gateway can propagate that header to the service to preserve the identity context.
HTTP rules primarily answer "can this identity call this API operation?". On their own they do not produce filters over the external service's database. To limit a route to a specific device, tenant or client, the schema must declare a constraint relating a request value to a normalized attribute of the principal.
Services developed by Lamassu
Lamassu's native services embed authorization in their middleware and know the entities they operate on: certificates, CAs, issuance profiles, keys, devices, DMSs or subscriptions, among others.
The decision is made with the domain operation context:
- The middleware extracts the credential and resolves the matching principals.
- The endpoint identifies the action, the entity type and, when applicable, the key of the requested resource.
authzgathers the entity rules of the granted policies.- The engine evaluates direct grants, attribute filters and relations with other entities.
- For an individual operation, it checks that the concrete resource satisfies the computed scope.
- For a listing, it generates a SQL filter that the service adds to its own query.
Here the engine answers "can this identity perform this action on this concrete resource?".
Actions fall into two groups:
- Global actions do not need a resource identifier.
create,importor access to a console section are common examples. - Atomic actions are evaluated on a concrete instance. For certificates these include
read,metadata-update,status-updateanddelete; for a CA there are alsosign,reissueand other lifecycle operations.
Filtering inside the service prevents leaks in listings: unauthorized resources are excluded from the SQL query instead of being fetched and hidden later in the interface.
How the two paths relate
They are not two equivalent controls applied twice. HTTP rules protect the perimeter of an integrated service; entity rules express permissions over the data model of the native services.
A policy can contain both rule types when an identity needs to operate Lamassu resources and also call an integrated API. Granting an entity rule does not automatically grant an HTTP action, nor does an HTTP rule create access over an entity.
Deny by default
If no combination of principal, policy and rule allows the operation, Lamassu denies it. Additionally, auth.externalAuthorization.failOpen is false by default: if authz is unavailable, the Gateway blocks protected routes.
OIDC principals
An OIDC principal matches the claims of a validated JWT. It is appropriate for human users, corporate groups, IdP roles and service accounts that obtain tokens.
The following principal represents any identity holding the pki-operators role in Keycloak:
{
"id": "oidc:pki-operators",
"name": "PKI Operators",
"description": "Team responsible for daily operation",
"type": "oidc",
"active": true,
"auth_config": {
"claims": [
{
"claim": "realm_access.roles",
"operator": "contains",
"value": "pki-operators"
}
]
}
}Claim paths can be nested, such as realm_access.roles. Within a single principal, all conditions must hold. This lets you require, for example, a group and an organizational audience at the same time.
The implemented operators are:
equals, for exact equality;contains, to check membership in a list or the presence of text in a scalar value.
Design matching with stable attributes. For people, it is usually better to bind permissions to centrally managed groups or roles than to the email or username. For a service account, a stable sub keeps its permissions from mixing with a human operator's.
Do not use matches yet
Although the model recognizes the operator name matches, the current implementation does not evaluate regular expressions and the condition never matches. Use equals or contains.
X.509 principals
An X.509 principal lets you recognize a workload or a device by its client certificate. Lamassu checks the certificate signature against the configured CA and, depending on the mode, also its serial number or Common Name.
The available modes are:
serial_and_ca: an exact certificate, identified by serial number and CA;cn_and_ca: an exact or wildcard Common Name and a specific CA;any_from_ca: any certificate issued directly by the given CA.
This example recognizes certificates whose CN starts with factory-a- and that are signed by the configured CA:
{
"id": "x509:factory-a-devices",
"name": "Factory A devices",
"type": "x509",
"active": true,
"auth_config": {
"match_mode": "cn_and_ca",
"subject_cn": "factory-a-*",
"ca_trust": {
"pem": "<CA-certificate-in-PEM-or-base64>",
"identity_type": "fingerprint",
"value": "SHA256:<sha256-fingerprint-of-the-ca>"
}
}
}ca_trust.identity_type accepts fingerprint or authority_key_id. In both cases you must provide the CA certificate in ca_trust.pem; Lamassu verifies both the signature and the expected identity of the CA.
Use any_from_ca only when every identity issued by that CA should share the same permissions. If a CA issues certificates for different populations, separate access by serial or CN, or use different issuing CAs.
When several principals match
A single credential can match more than one principal. It is common for a user to match a principal of their team and another of their operational function.
For entity permissions, Lamassu combines permissions with OR logic: it is enough that one policy of one of the principals allows the action. Listings contain the union of the resources visible to all of them.
HTTP routes with constraints are stricter. The same principal contributing the policy must also satisfy the attributes required by the route. Lamassu does not combine one principal's policy with an attribute belonging to another.
For this reason, adding a matching principal can only broaden access. Before creating overlapping rules, review the full set of policies a real identity will receive.
How policies express access
Global and direct access
A rule identifies the domain (namespace), the data schema (schema_name) and the entity type (entity_type). actions lists the allowed operations.
direct_grants limits the rule to concrete identifiers. The value * covers all instances of the type. A superadministrator policy uses wildcards in schema, entity, actions and grants; a least-privilege policy should avoid them whenever possible.
Access inherited through relations
Rules can follow relations declared between entities. For example, the schema knows the relation of a certificate to its issuing CA and of a device to its DMS. A policy can grant access to a parent resource and propagate selected actions to its related resources.
This lets you express models like "can operate the devices of this DMS" without maintaining an individual list of every device. When a resource is added under that relation, it inherits the scope planned by the policy.
Attribute-filtered access
column_filters applies conditions to columns the schema has declared filterable. All filters of the same rule are combined with AND.
For example, this rule allows reading active certificates issued by a specific CA:
{
"namespace": "pki",
"schema_name": "ca",
"entity_type": "certificate",
"actions": ["read"],
"relations": [],
"column_filters": [
{
"column": "status",
"type": "string",
"operator": "eq",
"value": "ACTIVE"
},
{
"column": "issuer_meta_id",
"type": "string",
"operator": "eq",
"value": "ca-production"
}
]
}The available operators are eq, neq, gt, gte, lt, lte, in and like. Use comparisons consistent with the column type: like for text, ordering comparisons for numbers or dates and in when there is a collection of accepted values.
HTTP rules
HTTP rules do not point directly at tables. They reference a route schema and grant its logical actions. Job Manager's policies are an example: they distinguish reading, creating, updating and deleting workflows or jobs.
Some routes also compare a request value — taken from the path, query, header or JSON body — with a normalized attribute of the principal. This way you can verify that a device only queries jobs addressed to its own client_id.
Normalized attributes decouple the policy from the authentication mechanism. subject_attribute_mappings can derive, for example, device_id from oidc.claim.device_id or from x509.subject.cn. The rule consumes device_id in both cases.
Included policies
The authz preload installs reusable policies for the main domains. Among them are:
- full and read-only access to certificates and authorities;
- full and read-only access to the KMS;
- full and read-only access to Device Manager, DMS Manager, Validation Authority and alerts;
- an
Auditorpolicy with PKI read access and authorization visibility; - console access;
- administration and observation policies for the Job Manager NBI and SBI APIs;
SUPER ADMIN, which grants all actions over theauthzandpkidomains.
Start with these policies before creating others. If none reflects the boundary you need, create a specific, small policy instead of copying SUPER ADMIN and informally removing permissions.
Provision the first administrator
There is no implicit superuser
An installation without a principal matching your identity is left with nobody able to administer authorization. Configure the IdP and the bootstrap before exposing the platform.
The chart includes a bootstrap principal that looks for the OIDC role pki-admin in realm_access.roles. It grants it SUPER ADMIN and, when Job Manager is enabled, the administrative policy of its NBI API.
auth:
authorization:
rolesClaim: realm_access.roles
roles:
admin: pki-admin
externalAuthorization:
enabled: true
failOpen: false
services:
authz:
jwkUrl: https://idp.example.com/realms/iot/protocol/openid-connect/certs
bootstrap:
- principal_id: "oidc:pki-admin"
principal_name: "PKI Admin"
principal_type: "oidc"
policy_ids:
# SUPER ADMIN
- "lamassu.a6811b60-5f89-4ce7-badb-78ea234794d3"
# Job Manager - Mgmt NBI Admin
- "lamassu.7df018c1-3140-4a35-9067-2e7d6cec3ed2"
auth_config:
claims:
- claim: "realm_access.roles"
operator: "contains"
value: "pki-admin"The pre-install and pre-upgrade Helm Job runs the authz migrations, preloads the policies and creates the bootstrap principals before the services start. If the principal already exists, it does not replace it: it only adds the configured grants that are still missing. You can keep the entry in values.yaml across upgrades.
Prepare the identity provider
Create the role or group you will use to administer Lamassu. Assign it to at least two controlled human identities. If your provider does not use realm_access.roles, adapt the claim path in both the frontend and auth_config.claims.
Configure the two JWT validations
The Gateway uses auth.authentication.apiGateway.jwks to authenticate requests. authz uses services.authz.jwkUrl to resolve OIDC principals. Both endpoints must contain the keys of the same issuer and be reachable from their respective components.
Install and verify administrative access
Sign in with an identity holding pki-admin. Confirm it can access authorization administration and perform a non-destructive read operation.
Test an unprivileged identity
Use a second user without the role and confirm the same operation is denied. This test catches misread claims, overly broad policies and accidental failOpen configurations.
Reduce use of the bootstrap administrator
Create operational principals with narrower policies. Reserve pki-admin for authorization administration and recovery, not for daily work.
Fastlane bootstrap
Fastlane installs a Keycloak realm for the lab and creates the user lamassu with the temporary password lamassu, the role pki-admin and a mandatory password change. Its bootstrap principal matches through preferred_username=lamassu.
Credentials for bootstrap only
Change the password on first login. Do not reuse the Fastlane user, password or IdP as a production design.
Design least-privilege roles
Avoid reproducing your company's internal structure with dozens of nearly identical policies. Start from the responsibilities that actually need access:
- Authorization administration: manages principals, policies and grants. It should belong to a small, separate group.
- PKI operation: administers CAs, profiles and certificates, but not necessarily who gets access.
- Device registration: operates devices and DMSs without receiving permissions over keys or authorization configuration.
- Audit: reviews configuration and activity without creating, modifying, signing, revoking or deleting.
- Automation: uses a technical account or a separate certificate, with permissions limited to the flow and resources it controls.
For each role, separate "view" from "change", limit resources through grants, relations or attributes and avoid * unless the role must automatically cover future actions.
Wildcards also grant future actions
A rule with actions: ["*"] expands to every action defined by the schema. When a new version adds an action, a wildcard policy may start granting it. Review these policies on every upgrade.
Changes and access revocation
To revoke access immediately, disable the principal or revoke its grants. Disabling a principal keeps its configuration and associations for investigation or restoration, but it stops taking part in matching.
Deleting a role or group in the IdP prevents new tokens from containing the claim, but an already-issued token may remain valid until it expires. If removal is urgent, combine the IdP change with disabling the principal in Lamassu and revoking sessions or tokens at the provider.
When you edit a shared policy, remember the change affects all its principals. To test a new scope, create a separate policy, grant it to a test identity and validate allowed and denied operations before replacing the old one.
Operational checklist
- Keep
failOpen: falseunless a documented risk assessment justifies otherwise. - Use groups or stable roles for people and independent identities for automations.
- Keep at least two recovery administrators and test their access periodically.
- Review active principals, their matches and their grants after IdP changes.
- Search for wildcards in policies before upgrading Lamassu.
- Always test one allowed and one denied operation for each role.
- Correlate changes to principals, policies and grants with the audit logs.
Diagnostics
The response is 401
Authentication failed before permissions were evaluated. Check the JWT signature and expiration, issuer, audience and the availability of the JWKS configured in the Gateway. For X.509, check that the client certificate reaches the point that extracts the credential.
The response is 403
The credential could be processed but did not produce a positive authorization. Review in this order:
- that an active principal of the correct type exists;
- that the claim paths and values match the real token exactly;
- that all of the principal's conditions hold;
- that the principal has the expected policy granted;
- that the policy includes the action and the requested resource type or route;
- that the identifier, relation, column filter or HTTP constraint includes the real resource.
In the authz logs, an external endpoint decision includes allowed, reason, matched_principals, evaluated_policy_ids, matched_policy_id and the status code. These fields let you separate a matching failure from a permissions failure.
Everything returns 403
Check that the bootstrap principal was created and that the policies were preloaded by the migration Job. Also verify that services.authz.jwkUrl is reachable from the authz pod; do not assume that a URL accessible from the browser also works inside the cluster.
Everything fails when authz is unavailable
This is the expected behavior with failOpen: false. Restore the service, its PostgreSQL connection and its JWKS connectivity. Do not temporarily switch to failOpen: true without accepting that protected routes could become accessible without an authorization decision.
Continue with Audit logs to investigate configuration changes or with Troubleshooting to diagnose the deployment.