PalC implements IAM at the protocol and platform level - FIDO2 CTAP flows, JIT PAM with Vault, OPA-based policy enforcement for API access, and OIDC federation with RBAC-integrated Kubernetes authentication.
Authentication - FIDO2 / WebAuthn Passwordless
Phishing-resistant passwordless with hardware security keys
WebAuthn credential registration and assertion flow - CTAP2 hardware key generates cryptographic proof bound to origin, preventing credential phishing and replay attacks.
// WebAuthn - credential creation (registration)
const credential = await navigator.credentials.create({
publicKey: {
rp: { name: "PalC Platform", id: "platform.palc.internal" },
user: { id: userId, name: userEmail },
challenge: serverChallenge, // random, server-generated
pubKeyCredParams: [{ type: "public-key", alg: -7 }, { type: "public-key", alg: -257 }],
authenticatorSelection: { authenticatorAttachment: "cross-platform", userVerification: "required", residentKey: "required" }
}
});StandardFIDO2 / WebAuthnAuthenticatorYubiKey - Titan KeyCryptoES256 / RS256PhishingOrigin-bound
PAM - Just-in-Time Access with HashiCorp Vault
Ephemeral credentials - no standing SSH keys or passwords
Vault dynamic secrets generate short-lived SSH certificates bound to the requestor's identity - no shared keys, every access audited, certificates expire after the approved session window.
# Vault - dynamic SSH certificate signing
vault write ssh/sign/admin-role public_key=@~/.ssh/id_ed25519.pub valid_principals="ubuntu" ttl=1h
# expires after 1 hour
# Approval workflow - Slack-gated JIT request
vault policy write jit-access - <<EOF
path "ssh/sign/admin-role" { capabilities = ["create", "update"] required_parameters = ["approval_id"] }
EOF
# Session recorded, certificate identity loggedVaultDynamic SSH certsTTLTime-bounded JITApprovalSlack / ticketedAuditSession recorded
Authorisation - OPA Rego Policy for API Access Control
Fine-grained API authorisation with identity-aware OPA policies
OPA evaluates JWT claims against Rego policy at every API call - role and scope enforcement with full attribute context, audit log on every deny decision, no hardcoded ACLs in application code.
# OPA Rego - JWT-based API access policy
package authz.api
default allow = false
allow {
# Verify JWT from OIDC IdP
token := io.jwt.decode(input.token)
claims := token[1]
# Role must match endpoint requirement
required_role := data.endpoints[input.path].role
claims.roles[_] == required_role
# Scope must be present in token
required_scope := data.endpoints[input.path].scope
claims.scopes[_] == required_scope
}
# Denied requests -> audit trail via OPA decision logEngineOPA / RegoTokenJWT / OIDCModelRBAC + ABACAuditDecision log
Federation - OIDC + Kubernetes RBAC Integration
Corporate IdP as the authoritative source for K8s access
Kubernetes API server configured to validate OIDC tokens from the corporate IdP - group membership in Azure AD / Okta maps directly to ClusterRoleBindings, eliminating static kubeconfig credentials.
# kube-apiserver - OIDC configuration
--oidc-issuer-url=https://login.microsoftonline.com/TENANT_ID/v2.0
--oidc-client-id=kubernetes-api-server
--oidc-groups-claim=groups
--oidc-username-claim=email
# ClusterRoleBinding - map AD group to K8s role
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
roleRef:
kind: ClusterRole
name: platform-ops
subjects:
- kind: Group
name: "azure-group-id-here"
IdPAzure AD - OktaProtocolOIDC / OAuth2AuthzK8s RBACNo Statickubeconfig keys