Skip to content
Open
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
3 changes: 2 additions & 1 deletion .github/workflows/on-pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ jobs:
examples: |
[
{ "example": "examples/gitkbs/minimal.yaml" },
{ "example": "examples/gitkbs/standard.yaml" }
{ "example": "examples/gitkbs/standard.yaml" },
{ "example": "examples/gitkbs/with-istio-jwt.yaml" }
]
api_path: apis/gitkbs
error_on_missing_schemas: true
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/on-push-main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ jobs:
examples: |
[
{ "example": "examples/gitkbs/minimal.yaml" },
{ "example": "examples/gitkbs/standard.yaml" }
{ "example": "examples/gitkbs/standard.yaml" },
{ "example": "examples/gitkbs/with-istio-jwt.yaml" }
]
api_path: apis/gitkbs
error_on_missing_schemas: true
Expand Down
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ generate-configuration:

EXAMPLES := \
examples/gitkbs/minimal.yaml:: \
examples/gitkbs/standard.yaml::
examples/gitkbs/standard.yaml:: \
examples/gitkbs/with-istio-jwt.yaml::

render\:all:
@tmpdir=$$(mktemp -d); \
Expand Down
64 changes: 63 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,44 @@ spec:
kind: ClusterIssuer
```

Authentication is intentionally not part of this pass. Public installs should add Gateway/OIDC policy before exposing writable GitKB sync traffic beyond trusted networks.
For Istio ambient clusters, enable a dedicated GitKB Zitadel client with
`auth.oidcClient`, then enable service-level JWT enforcement with
`auth.istioJwt`. This renders:

- a GitKB-owned Zitadel Project
- a native public OIDC Application for CLI device login
- a Role, MachineUser, and Grant for automation sync
- ambient enrollment on the GitKB namespace
- waypoint labels on the chart-owned GitKB Service
- an Istio waypoint `Gateway`
- service-targeted `RequestAuthentication` using the GitKB Project ID as an audience
- service-targeted `AuthorizationPolicy` requiring a valid JWT

```yaml
spec:
auth:
oidcClient:
enabled: true
issuer: https://auth.ops.com.ai
jwksUri: https://auth.ops.com.ai/oauth/v2/keys
zitadelProviderConfigRef:
name: zitadel-tenant-stack
kind: ProviderConfig
zitadelOrgId: "373268222482392664"
projectName: gitkb
device:
applicationName: gitkb-cli
machine:
userName: gitkb-sync
istioJwt:
enabled: true
```

This protects the workload for requests that carry a valid bearer token issued
for the GitKB Project audience. Configure the GitKB CLI remote with the Project
audience scope, the device-flow client ID from
`status.auth.oidcClient.device.clientSecretRef`, and the machine credentials
from `status.auth.oidcClient.machine.clientSecretRef`.

## Import Existing

Expand All @@ -113,6 +150,21 @@ Configure the GitKB CLI remote to the status URL or to the same domain and repo
```toml
[sync.remotes.origin]
url = "https://kb.ops.com.ai/hops-ops/hops"

[sync.remotes.origin.auth]
issuer = "https://auth.ops.com.ai"
scopes = [
"openid",
"profile",
"urn:zitadel:iam:org:project:id:<status.auth.oidcClient.projectId>:aud",
]

[sync.remotes.origin.auth.device]
client_id = "<client_id from status.auth.oidcClient.device.clientSecretRef>"

[sync.remotes.origin.auth.machine]
client_id = "gitkb-sync"
client_secret_env = "GITKB_OIDC_CLIENT_SECRET"
```

The server route strips `/hops-ops/hops` before forwarding traffic to `git-kb serve`, so the CLI talks to the normal GitKB endpoints under that public path.
Expand All @@ -129,13 +181,23 @@ The XR publishes the operational fields needed by downstream automation:
- `status.exposure.url` - full public URL for the GitKB remote.
- `status.exposure.routeReady` - composed HTTPRoute readiness.
- `status.exposure.certificateReady` - composed Certificate readiness when enabled.
- `status.auth.oidcClient` - GitKB-owned Zitadel Project audience, device-flow client Secret reference, machine credential Secret reference, and readiness.
- `status.auth.istioJwt` - whether Istio JWT auth rendered and whether the waypoint and policies are ready.

## Composed Resources

- `helm.m.crossplane.io/Release` - installs the `gitkb-server` chart.
- `kubernetes.m.crossplane.io/Object` Namespace - creates the target namespace.
- `kubernetes.m.crossplane.io/Object` HTTPRoute - optional Gateway API route when `exposure.enabled` is true.
- `kubernetes.m.crossplane.io/Object` Certificate - optional cert-manager Certificate when `exposure.certificate.enabled` is true.
- `project.zitadel.m.crossplane.io/Project` - optional GitKB Project when `auth.oidcClient.enabled` is true.
- `application.zitadel.m.crossplane.io/Oidc` - optional native public OIDC app for CLI device login when `auth.oidcClient.enabled` is true.
- `project.zitadel.m.crossplane.io/Role` - optional GitKB sync Role when `auth.oidcClient.enabled` is true.
- `user.zitadel.m.crossplane.io/MachineUser` - optional GitKB OAuth2 client when `auth.oidcClient.enabled` is true.
- `user.zitadel.m.crossplane.io/Grant` - optional Role grant to the GitKB MachineUser when `auth.oidcClient.enabled` is true.
- `kubernetes.m.crossplane.io/Object` Gateway - optional Istio waypoint when `auth.istioJwt.enabled` and `issuer` are set.
- `kubernetes.m.crossplane.io/Object` RequestAuthentication - optional JWT validation policy when `auth.istioJwt.enabled` and `issuer` are set.
- `kubernetes.m.crossplane.io/Object` AuthorizationPolicy - optional valid-JWT requirement when `auth.istioJwt.enabled` and `issuer` are set.
- `protection.crossplane.io/Usage` - protects dependency deletion order once resources are ready.

## Development
Expand Down
201 changes: 199 additions & 2 deletions apis/gitkbs/definition.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ spec:
description: Helm release name for the gitkb-server chart. Defaults to metadata.name.
type: string
chartVersion:
description: Version of the gitkb-server chart. Defaults to "0.1.0".
description: Version of the gitkb-server chart. Defaults to "0.2.1".
type: string
gitkb:
description: GitKB runtime settings passed to the chart.
Expand Down Expand Up @@ -165,7 +165,7 @@ spec:
type: boolean
default: true
exposure:
description: Optional unauthenticated Gateway API exposure. Public exposure is intentionally unauthenticated in this pass; add Gateway/OIDC policy in a later pass.
description: Optional Gateway API exposure. Pair with auth.istioJwt for Istio ambient JWT enforcement before broad public use.
type: object
properties:
enabled:
Expand Down Expand Up @@ -235,6 +235,118 @@ spec:
- Issuer
- ClusterIssuer
default: ClusterIssuer
auth:
description: Optional authentication and mesh-policy resources for GitKB sync traffic.
type: object
properties:
oidcClient:
description: |
Dedicated Zitadel identities for GitKB CLI sync. When
enabled, the composition creates its own Zitadel Project,
native OIDC device-flow Application, sync Role,
MachineUser, and Grant. Human users authenticate through
the device-flow Application; automation authenticates
through the MachineUser client_credentials identity.
type: object
properties:
enabled:
description: Render the GitKB-owned Zitadel client identity.
type: boolean
default: false
issuer:
description: Expected OAuth/OIDC issuer, for example https://auth.ops.com.ai.
type: string
jwksUri:
description: JWKS URI for the issuer. If omitted, Istio may use OIDC discovery.
type: string
zitadelProviderConfigRef:
description: Zitadel ProviderConfig used to provision the Project, device Application, Role, MachineUser, and Grant.
type: object
properties:
name:
type: string
kind:
type: string
default: ProviderConfig
zitadelOrgId:
description: Zitadel Org ID that owns the GitKB Project, device Application, and MachineUser.
type: string
projectName:
description: Zitadel Project name. Defaults to <releaseName>-gitkb.
type: string
roleKey:
description: Zitadel Role key granted to the GitKB MachineUser.
type: string
default: gitkb:sync
device:
description: Human device-flow OIDC Application settings.
type: object
properties:
applicationName:
description: Zitadel native OIDC Application name for GitKB CLI device login. Defaults to <releaseName>-cli.
type: string
clientSecretName:
description: Connection Secret containing the generated device-flow client_id and client_secret. Defaults to <applicationName>-oidc-client.
type: string
redirectUris:
description: Redirect URIs to set on the native OIDC Application. Defaults to ["http://localhost"] because the Zitadel provider requires at least one redirect URI even when device flow is used.
type: array
items:
type: string
responseTypes:
description: Response types to set on the native OIDC Application. Defaults to ["OIDC_RESPONSE_TYPE_CODE"] because the Zitadel provider requires at least one response type even when device flow is used.
type: array
items:
type: string
machine:
description: Automation MachineUser settings for client_credentials sync.
type: object
properties:
userName:
description: MachineUser username. This becomes the OAuth2 client_id. Defaults to <releaseName>-sync.
type: string
clientSecretName:
description: Connection Secret name for client credentials. Defaults to <userName>-secret.
type: string
istioJwt:
description: Istio ambient waypoint JWT enforcement for the GitKB Service. Requires an Istio ambient mesh and a valid issuer/JWKS configuration.
type: object
properties:
enabled:
description: Render ambient namespace labels, service waypoint labels, a waypoint Gateway, RequestAuthentication, and AuthorizationPolicy.
type: boolean
default: false
issuer:
description: Expected JWT issuer, for example https://auth.ops.com.ai.
type: string
jwksUri:
description: JWKS URI for the issuer. If omitted, Istio may use OIDC discovery for issuers that support it.
type: string
audiences:
description: Optional JWT audiences accepted by Istio, for example a Zitadel project ID.
type: array
items:
type: string
useOidcClientAudience:
description: Add the GitKB-owned Zitadel Project ID to accepted audiences once observed. Has no effect unless auth.oidcClient.enabled is true. Defaults to true.
type: boolean
default: true
requestPrincipals:
description: Request principals allowed by the AuthorizationPolicy. Defaults to ["*"] to require any valid JWT.
type: array
items:
type: string
waypoint:
description: Istio waypoint settings.
type: object
properties:
name:
description: Waypoint Gateway name. Defaults to <releaseName>-waypoint.
type: string
gatewayClassName:
description: GatewayClass used for the waypoint. Defaults to istio-waypoint.
type: string
default: istio-waypoint
values:
description: Helm values merged over stack defaults for the gitkb-server chart.
type: object
Expand Down Expand Up @@ -288,5 +400,90 @@ spec:
type: boolean
certificateReady:
type: boolean
auth:
type: object
properties:
oidcClient:
type: object
properties:
enabled:
type: boolean
rendered:
type: boolean
issuer:
type: string
projectId:
description: Observed Zitadel Project ID. Use as the audience scope with urn:zitadel:iam:org:project:id:<projectId>:aud.
type: string
device:
description: Observed human device-flow OIDC Application details.
type: object
properties:
applicationId:
description: Observed Zitadel Application ID.
type: string
clientSecretRef:
description: Secret containing the generated device-flow client_id and client_secret.
type: object
properties:
name:
type: string
namespace:
type: string
clientIdKey:
type: string
clientSecretKey:
type: string
ready:
type: boolean
machine:
description: Observed automation MachineUser client credentials.
type: object
properties:
clientId:
description: Observed OAuth2 client_id for GitKB CLI client_credentials authentication.
type: string
userId:
description: Observed Zitadel MachineUser ID.
type: string
clientSecretRef:
description: Secret containing the MachineUser client credentials.
type: object
properties:
name:
type: string
namespace:
type: string
clientIdKey:
type: string
clientSecretKey:
type: string
ready:
type: boolean
projectReady:
type: boolean
roleReady:
type: boolean
grantReady:
type: boolean
istioJwt:
type: object
properties:
enabled:
type: boolean
rendered:
type: boolean
issuer:
type: string
audiences:
type: array
items:
type: string
waypointReady:
type: boolean
requestAuthenticationReady:
type: boolean
authorizationPolicyReady:
type: boolean
required:
- spec
35 changes: 35 additions & 0 deletions examples/gitkbs/with-istio-jwt.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
apiVersion: hops.ops.com.ai/v1alpha1
kind: GitKB
metadata:
name: platform-kb-auth
namespace: default
spec:
clusterName: pat-local
namespace: gitkb
gitkb:
org: hops-ops
repo: hops
name: Hops Knowledge Base
exposure:
enabled: true
domain: kb.ops.com.ai
gatewayRef:
name: platform
namespace: istio-ingress
sectionName: https
auth:
oidcClient:
enabled: true
issuer: https://auth.ops.com.ai
jwksUri: https://auth.ops.com.ai/oauth/v2/keys
zitadelProviderConfigRef:
name: zitadel-tenant-stack
kind: ProviderConfig
zitadelOrgId: "373268222482392664"
projectName: gitkb
device:
applicationName: gitkb-cli
machine:
userName: gitkb-sync
istioJwt:
enabled: true
Loading
Loading