Pinniped: Autenticação Federada para Clusters Kubernetes

Gerir quem acede aos clusters Kubernetes é um dos maiores desafios de segurança em infraestruturas modernas. O Pinniped, mantido pela VMware (Tanzu), resolve este problema ao federar a autenticação com Fornecedores de Identidade existentes — Entra ID, Okta, Kanidm ou LDAP — eliminando certificados de cliente longevos e trazendo SSO com códigos de acesso de curta duração ao kubectl.

ℹ Para quem é este artigo: Administradores Kubernetes e equipas de segurança em PMEs que precisam de integrar clusters com identidade corporativa (Entra ID, Okta, Kanidm) sem gerir certificados de cliente manualmente.

Neste artigo

1. Introdução — O problema de acesso ao Kubernetes

O modelo de autenticação nativo do Kubernetes baseia-se em certificados de cliente X.509 emitidos pelo cluster. Cada utilizador ou serviço que precise de aceder ao API server recebe um certificado assinado pela CA do cluster. Este modelo tem três problemas fundamentais para PMEs:

Certificados longevos sem revogação. O Kubernetes não implementa revogação de certificados (CRL/OCSP). Um certificado de cliente válido até 2028 continua a funcionar mesmo depois de o utilizador deixar a empresa, a menos que se recrie a CA inteira — operação disruptiva.

Gestão manual descentralizada. Cada cluster mantém a sua própria lista de certificados. Numa PME com 3 clusters de desenvolvimento, pré-produção e produção, um administrador que saia da empresa exige revogação manual em cada cluster — frequentemente esquecida.

Ausência de SSO. O kubectl não integra nativamente com Entra ID, Okta ou qualquer IdP baseado em OIDC. As equipas acabam por partilhar kubeconfig files com credenciais embutidas, violando princípios básicos de segregação de acesso.

O Pinniped resolve estes três problemas ao funcionar como intermediário entre o kubectl e o IdP corporativo, emitindo credenciais de curta duração (o login inicial consome-se em cerca de 19 minutos e as sessões continuam via refresh token de 9 horas, conforme as durações fixas documentadas) que se renovam automaticamente a partir de uma sessão SSO válida.

2. O que é o Pinniped

O Pinniped é um serviço de autenticação federada de código aberto para Kubernetes, mantido pela VMware (Tanzu, organização vmware-tanzu no GitHub) e licenciado sob Apache 2.0. O nome provém do inglês para “pinípede” (focas, leões-marinhos), criaturas conhecidas pela sua capacidade de autenticação mútua — uma analogia à federação de identidade.

Característica Descrição
Manutenção e licença VMware (Tanzu) · Apache 2.0
Licença Apache 2.0
IdPs suportados Entra ID (Azure AD), Okta, GitHub, LDAP, Active Directory (via LDAP), qualquer IdP OIDC
Modelo de códigos Durações fixas: auth code 10 min, ID/access token 2 min, credencial de cluster 5 min, refresh 9 h
Instalação kubectl apply dos YAMLs oficiais (get.pinniped.dev), sem dependências externas
Cliente Plugin kubectl (pinniped-cli), sem alterações ao kubectl

A vantagem principal para PMEs é a reutilização da identidade corporativa. Em vez de criar utilizadores Kubernetes independentes, o Pinniped delega a autenticação no IdP que a empresa já usa. Quando um colaborador é desactivado no Entra ID ou Kanidm, perde automaticamente acesso a todos os clusters federados — sem necessidade de revogar certificados manualmente.

O Pinniped suporta dois tipos de IdP: OIDC (Entra ID, Okta, qualquer fornecedor OAuth 2.0/OIDC) e LDAP (directório tradicional, Kanidm em modo LDAP). A configuração é feita via Custom Resource Definitions (CRDs) no cluster, sem necessidade de recompilar ou modificar o Kubernetes.

3. Arquitectura e Componentes

O Pinniped tem uma arquitectura de três componentes que funcionam em conjunto para fornecer autenticação federada:

3.1 Supervisor

O Pinniped Supervisor é o componente central. Corre dentro do cluster Kubernetes como Deployment e expõe um endpoint de autenticação. É responsável por:

  • Comunicar com o IdP externo (Entra ID, Okta, LDAP) via OIDC ou LDAP bind
  • Validar as credenciais do utilizador contra o IdP
  • Emitir códigos de acesso JWT de curta duração assinados pela sua própria chave
  • Renovar códigos de acesso expirados via refresh, sem nova autenticação do utilizador

3.2 Concierge

O Pinniped Concierge é o componente que corre em cada cluster alvo (onde os utilizadores querem executar kubectl). Funciona como API de troca de credenciais (TokenCredentialRequest): o kubectl envia um pedido com um token emitido pelo Supervisor, o Concierge valida a assinatura do ID token federado (via JWTAuthenticator) e devolve uma credencial de curta duração entendida pelo API server.

3.3 Pinniped CLI

O pinniped-cli é um plugin de kubectl que o utilizador instala na sua máquina. Gere o fluxo de autenticação: abre o navegador para iniciar sessão no IdP, recebe o código de autorização, troca-o por um código de acesso do Supervisor, e configura o kubeconfig para usar o Concierge via TokenCredentialRequest.

ℹ O fluxo de autenticação é transparente para o utilizador: após executar pinniped login uma vez, o kubectl funciona normalmente. Os códigos de acesso são renovados em background sem intervenção do utilizador, enquanto a sessão SSO for válida.

O diagrama seguinte ilustra o fluxo de autenticação completo:

Utilizador       Pinniped CLI      Supervisor        IdP (Entra ID)     Concierge      K8s API
    |                |                  |                  |                 |              |
    | kubectl get pods|                  |                  |                 |              |
    |--------------->|                  |                  |                 |              |
    |                | sem código válido |                  |                 |              |
    |                |----------------->|                  |                 |              |
    |                |                  | redirect OIDC    |                 |              |
    |                |<-----------------|                  |                 |              |
    | abrir navegador|                  |                  |                 |              |
    |<---------------|                  |                  |                 |              |
    | login (user+MFA)                  |                  |                 |              |
    |----------------------------------------------------->|                 |              |
    | código autorização                |                  |                 |              |
    |<-----------------------------------------------------|                 |              |
    |                | exchange code     |                  |                 |              |
    |                |----------------->|                  |                 |              |
    |                |                  | tokens OIDC      |                 |              |
    |                |                  |----------------->|                 |              |
    |                |                  |<-----------------|                 |              |
    |                | ID + access token |                  |                 |              |
    |                |<-----------------|                  |                 |              |
    |                | request + token  |                  |                 |              |
    |                |------------------------------------------------->|              |
    |                |                  |                  |                 | valida JWT   |
    |                |                  |                  |                 |------------->|
    |                |                  |                  |                 | 200 OK      |
    |                |<-------------------------------------------------|              |
    | pods list      |                  |                  |                 |              |
    |<---------------|                  |                  |                 |              |

4. Configuração com Entra ID

A configuração com Microsoft Entra ID (antigo Azure AD) é o cenário mais comum em PMEs que já usam Microsoft 365. O processo envolve três passos: registar uma aplicação no Entra ID, instalar o Pinniped no cluster, e configurar o Supervisor com as credenciais da aplicação.

4.1 Registo da aplicação no Entra ID

No portal do Entra ID (entra.microsoft.com), criar um novo registo de aplicação com:

  • Nome: Pinniped Kubernetes Auth
  • Tipo de conta: Contas neste directório organizacional apenas
  • URI de redireccionamento: https://<supervisor-endpoint>/callback

Anotar o Application (client) ID e o Directory (tenant) ID. Criar um secret de cliente e anotar o valor. Estes três valores são necessários para configurar o Supervisor.

4.2 Instalação do Pinniped no cluster

Instalar o Supervisor e o Concierge via YAML oficial (método único documentado):

# Instalar o Supervisor (YAML oficial da release; substituir pela versão desejada)
kubectl apply -f https://get.pinniped.dev/v0.47.0/install-pinniped-supervisor.yaml

# Instalar o Concierge no cluster alvo
kubectl apply -f https://get.pinniped.dev/v0.47.0/install-pinniped-concierge.yaml

# Instalar o CLI localmente (tap oficial)
brew install vmware/pinniped/pinniped-cli   # macOS/Linux
# ou: binários em https://github.com/vmware-tanzu/pinniped/releases

4.3 Configuração do Supervisor com Entra ID

Criar um Secret com as credenciais do Entra ID e uma FederationDomain que referencia o IdP OIDC:

# Secret com client ID e client secret do Entra ID
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: entra-id-client-credentials
  namespace: pinniped-supervisor
type: secrets.pinniped.dev/oidc-client
stringData:
  clientID: "11111111-2222-3333-4444-555555555555"
  clientSecret: "client-secret-value-here"
EOF

# Configurar o IdP OIDC no Supervisor
cat <<EOF | kubectl apply -f -
apiVersion: idp.supervisor.pinniped.dev/v1alpha1
kind: OIDCIdentityProvider
metadata:
  name: entra-id
  namespace: pinniped-supervisor
spec:
  issuer: "https://login.microsoftonline.com/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/v2.0"
  authorizationConfig:
    additionalScopes: ["offline_access", "groups"]
  claims:
    groups: "groups"
    username: "preferred_username"
  client:
    secretName: entra-id-client-credentials
EOF

# Criar FederationDomain (expõe o endpoint do Supervisor)
cat <<EOF | kubectl apply -f -
apiVersion: config.supervisor.pinniped.dev/v1alpha1
kind: FederationDomain
metadata:
  name: kbase-federation
  namespace: pinniped-supervisor
spec:
  issuer: "https://pinniped-supervisor.kbase.pt"
  tls:
    secretName: pinniped-supervisor-tls   # Secret tipo kubernetes.io/tls (tls.crt/tls.key)
  identityProviders:
    - displayName: "Entra ID Corporativo"
      objectRef:
        apiGroup: idp.supervisor.pinniped.dev
        kind: OIDCIdentityProvider
        name: entra-id
EOF

⚠ O issuer do FederationDomain deve corresponder ao URL onde o Supervisor está acessível. Se o cluster estiver atrás de um ingress ou load balancer, garantir que o TLS está configurado correctamente — o Pinniped exige HTTPS para o endpoint do Supervisor. O Secret pinniped-supervisor-tls referenciado acima tem de existir no namespace com as chaves tls.crt e tls.key (o demo oficial usa cert-manager para o criar).

4.4 Configuração do Concierge e kubeconfig

Após o Supervisor estar configurado, ligar o Concierge ao Supervisor e gerar o kubeconfig para os utilizadores:

# Configurar o Concierge para confiar no Supervisor
cat <<EOF | kubectl apply -f -
apiVersion: authentication.concierge.pinniped.dev/v1alpha1
kind: JWTAuthenticator
metadata:
  name: pinniped-supervisor
spec:
  issuer: "https://pinniped-supervisor.kbase.pt"
  audience: "kbase-k8s"
  tls:
    certificateAuthorityData: "$(kubectl get secret -n pinniped-supervisor \
      pinniped-supervisor-tls -o jsonpath='{.data.ca\.crt}' | base64 -d | base64 -w0)"
EOF

# Gerar kubeconfig para os utilizadores utilizarem
pinniped get kubeconfig \\
  --kubeconfig ~/.kube/config-prod \\
  > pinniped-kubeconfig.yaml

# Distribuir pinniped-kubeconfig.yaml aos utilizadores.
# Cada utilizador executa:
KUBECONFIG=pinniped-kubeconfig.yaml kubectl get pods
# Isto abre o navegador para login no Entra ID.

A partir deste momento, o kubectl usa o Pinniped para autenticar. O utilizador inicia sessão uma vez no navegador, recebe um código de acesso JWT de curta duração, e o Pinniped renova-o automaticamente enquanto a sessão for válida.

5. Configuração com Kanidm/LDAP

Para PMEs que não usam Entra ID — tipicamente infraestruturas auto-alojadas com Kanidm ou LDAP tradicional — o Pinniped suporta autenticação via LDAP bind. Esta secção cobre a configuração com Kanidm em modo LDAP, que é o cenário mais comum em PMEs que preferem soluções de código aberto auto-alojadas.

5.1 Configuração LDAP com Kanidm

O Kanidm expõe uma interface LDAP compatível — a porta é configurável no server.toml (3636 é o padrão da documentação) e o LDAP reutiliza o material TLS do servidor web. Criar um LDAPIdentityProvider no Supervisor:

# Secret com bind credentials para pesquisa LDAP no Kanidm
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: kanidm-bind-credentials
  namespace: pinniped-supervisor
type: kubernetes.io/basic-auth
stringData:
  username: "uid=pinniped-bind,ou=people,dc=kbase,dc=pt"
  password: "bind-password-here"
EOF

# Configurar LDAPIdentityProvider
cat <<EOF | kubectl apply -f -
apiVersion: idp.supervisor.pinniped.dev/v1alpha1
kind: LDAPIdentityProvider
metadata:
  name: kanidm-ldap
  namespace: pinniped-supervisor
spec:
  host: "kanidm.kbase.pt:3636"
  tls:
    caData: "$(base64 -w0 < kanidm-ca.crt)"
  bind:
    secretName: kanidm-bind-credentials
  userSearch:
    base: "ou=people,dc=kbase,dc=pt"
    filter: "(objectClass=person)"
    attributes:
      username: "mail"
      uid: "entryuuid"
  groupSearch:
    base: "ou=groups,dc=kbase,dc=pt"
    filter: "(objectClass=group)"
    attributes:
      groupName: "cn"
EOF

ℹ O Kanidm suporta também OIDC nativo. Se preferir usar OIDC em vez de LDAP, configure um OIDCIdentityProvider com o issuer do Kanidm (https://kanidm.kbase.pt/oauth2/openid/pinniped). O OIDC oferece melhor rastreabilidade de sessões e suporte a MFA nativo.

5.2 Mapeamento de grupos

O Pinniped mapeia automaticamente os grupos do IdP para grupos Kubernetes. Isto permite usar RoleBindings e ClusterRoleBindings baseados em grupos do directório, em vez de utilizadores individuais:

# RoleBinding baseado em grupo do Kanidm/Entra ID
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: k8s-admins
subjects:
- kind: Group
  name: "k8s-admins"      # grupo no Kanidm ou Entra ID
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
EOF

Quando um utilizador do grupo k8s-admins no Kanidm inicia sessão via Pinniped, o código de acesso JWT inclui o grupo, e o Kubernetes aplica automaticamente as permissões definidas no ClusterRoleBinding.

6. Boas Práticas de Segurança

A implementação do Pinniped deve seguir boas práticas de segurança para garantir que a federação de identidade não introduz novos vectores de ataque:

Prática Recomendação Risco se ignorada
Duração dos códigos Fixas no Supervisor (10 min auth code, 2 min tokens, 9 h refresh) — planear à volta delas Sessões mal dimensionadas se assumir valores configuráveis
MFA no IdP Activar MFA obrigatório no Entra ID/Kanidm Password comprometida dá acesso ao cluster
TLS no Supervisor Usar certificados válidos, não self-signed MITM intercepta códigos de acesso
RBAC por grupos Usar grupos do IdP, não utilizadores Permissões não acompanham saída da empresa
Isolamento do Supervisor Namespace dedicado, NetworkPolicy restrictiva Comprometimento do Supervisor afecta todos os clusters
Registos de auditoria Activar audit logging no Concierge e Supervisor Sem rastreabilidade de quem acedeu ao cluster

6.1 Duração dos tokens e credenciais (fixa, não configurável)

As durações de todos os tokens e credenciais do Pinniped são fixas no código do Supervisor e não são configuráveis — nenhum campo do FederationDomain as altera. Para um login inicial, a cadeia é: código de autorização válido 10 minutos, ID token e access token 2 minutos cada, e a credencial de cluster (certificado cliente mTLS emitido pelo Concierge) 5 minutos — cerca de 19 minutos no total para consumir o login. O refresh token tem 9 horas de validade a partir da autenticação inicial e é ele que sustenta as sessões contínuas do kubectl.

A única excepção à regra: clientes OIDC personalizados (CRD OIDCClient) podem definir spec.tokenLifetimes.idTokenSeconds para ajustar a duração dos ID tokens emitidos a esse cliente — disponível desde a v0.30.0, e não aplicável ao pinniped-cli, que usa sempre o cliente pinniped-cli fixo. Verificar a duração corrente nos logs do Supervisor ou nos eventos do cluster; planejar o sizing de sessões à volta dos valores fixos acima (documentação oficial de tokens e credenciais).

6.2 NetworkPolicy para isolamento

Aplicar uma NetworkPolicy para restringir o tráfego de e para o Supervisor: ingress apenas a partir do namespace do Concierge; egress limitado ao IdP externo e ao DNS:

cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: pinniped-supervisor-isolation
  namespace: pinniped-supervisor
spec:
  podSelector:
    matchLabels:
      app: pinniped-supervisor
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: pinniped-concierge
    ports:
    - protocol: TCP
      port: 8443
  egress:
  - to: []    # IdP externo (Entra ID, Kanidm)
    ports:
    - protocol: TCP
      port: 443
  - to: []    # DNS
    ports:
    - protocol: UDP
      port: 53
EOF

7. Conclusão

O Pinniped resolve um problema real e doloroso na gestão de clusters Kubernetes: a autenticação de utilizadores com certificados de cliente longevos e sem revogação. Ao federar a autenticação com IdPs corporativos (Entra ID, Okta, Kanidm, LDAP), as PMEs obtêm três benefícios concretos: códigos de acesso de curta duração que expiram automaticamente, SSO que elimina credenciais redundantes, e revogação centralizada — quando um utilizador é desactivado no IdP, perde acesso a todos os clusters federados.

A implementação é relativamente simples — três componentes (Supervisor, Concierge, CLI) configurados via CRDs — e não requer alterações ao código do Kubernetes ou ao kubectl. Para PMEs que já usam Entra ID ou Kanidm, o Pinniped é a forma mais directa de aplicar políticas de identidade corporativa ao acesso Kubernetes, alinhando-se com princípios Zero Trust sem custo de licenciamento.

Artigos relacionados:

Fontes oficiais: pinniped.dev · GitHub: vmware-tanzu/pinniped · Documentação Pinniped