Jenkins OIDC, Gitea OIDC e Grafana SSO com o Casdoor: Um único login para uma stack DevOps auto-hospedada
Cada ferramenta em uma típica stack DevOps auto-hospedada pode atuar como um cliente OpenID Connect: Gitea e Argo CD suportam OIDC nativamente, Jenkins faz isso através do plugin oic-auth, Grafana e Portainer através de OAuth 2.0 genérico, e MinIO, Harbor e GitLab através de suas configurações OIDC. Aponte todas elas para uma única instância do Casdoor, dê a cada ferramenta sua própria aplicação no Casdoor e coloque seus usuários em grupos do Casdoor. Cada ferramenta então lê a claim groups e decide quem é administrador. Este post lista a URL de callback, as chaves de configuração e o mapeamento de grupos para cada ferramenta, depois cobre as partes que elas compartilham.
A stack em resumo
Todos os caminhos abaixo são relativos à URL pública da própria ferramenta. Registre-os em Redirect URLs da aplicação do Casdoor correspondente a essa ferramenta.
| App | Protocol | Callback URL | Group/role to admin mapping | Casdoor doc |
|---|---|---|---|---|
| Gitea | OIDC (OAuth2 auth source) | /user/oauth2/<source-name>/callback | Sim: grupo admin, grupo restrito, mapa de equipe | Gitea |
| Jenkins | OIDC (oic-auth plugin) | /securityRealm/finishLogin, logout /OicLogout | Sim: claim de grupos mais segurança baseada em Matrix | Jenkins (OIDC) |
| Grafana | Generic OAuth 2.0 | /login/generic_oauth | Sim: role_attribute_path | Grafana |
| Argo CD | OIDC | /auth/callback, CLI http://localhost:8085/auth/callback | Sim: argocd-rbac-cm | Argo CD |
| MinIO | OIDC | Console /oauth_callback | Políticas de uma claim (claim_name) | MinIO |
| Portainer | OAuth 2.0 (Custom) | A URL base do Portainer | Apenas Business Edition | Portainer |
| Harbor | OIDC | /c/oidc/callback | Sim: OIDC Admin Group | ainda não disponível |
| GitLab | OIDC (OmniAuth) | /users/auth/openid_connect/callback | Premium e Ultimate: admin_groups | GitLab |
O documento de descoberta que todo cliente OIDC precisa é https://<casdoor-host>/.well-known/openid-configuration. Se você nunca conectou um cliente OIDC ao Casdoor antes, Connect a standard OIDC client explica os endpoints.
Prepare o Casdoor uma vez
Antes de tocar nas ferramentas, configure três coisas no Casdoor.
Groups. Crie grupos como devops-admins e devops-users na árvore da organização e adicione usuários a eles. Veja Groups.
Token group format. Por padrão, a claim groups nomeia cada grupo como <organization>/<group>. A maioria das ferramentas compara a claim com uma string simples que você digita, então defina Token group format na aba OIDC/OAuth de cada aplicação para Name (group). A claim então carrega devops-admins. As opções são descritas em Group format.
Token format. Mantenha Token format como JWT, o padrão. Nesse formato, o ID token carrega groups, roles e tag. JWT-Empty e JWT-Standard deixam todos os três fora do token, e JWT-Custom os carrega apenas se você selecioná-los em Token fields. A resposta /api/userinfo retorna groups e os nomes das roles quando o escopo profile é concedido, então ferramentas que leem userinfo ainda os veem.
Roles também funcionam. No formato JWT, a claim roles é um array de objetos de role, então combine com roles[*].name. Em /api/userinfo, é um array simples de nomes. Veja User roles.
Gitea
Em Site Administration, adicione uma fonte de autenticação do tipo OAuth2 com provedor OpenID Connect, o client ID e secret, e a URL de descoberta do Casdoor. O nome que você dá à fonte faz parte da URL de callback: uma fonte chamada casdoor usa https://gitea.example.com/user/oauth2/casdoor/callback.
Para o mapeamento de grupos, preencha Claim name providing group names com groups, depois Group Claim value for administrator users com devops-admins. O Gitea também tem Group Claim value for restricted users e Map claimed groups to Organization teams. A mesma fonte via CLI:
gitea admin auth add-oauth \
--name casdoor \
--provider openidConnect \
--key <client-id> \
--secret <client-secret> \
--auto-discover-url https://door.example.com/.well-known/openid-configuration \
--group-claim-name groups \
--admin-group devops-admins
Jenkins
O Jenkins não possui suporte OIDC próprio. Instale o plugin OpenId Connect Authentication, escolha-o como realm de segurança e use a configuração well-known. O callback de login é /securityRealm/finishLogin e o callback de logout é /OicLogout; adicione ambos ao Casdoor. No JCasC:
jenkins:
securityRealm:
oic:
serverConfiguration:
wellKnown:
wellKnownOpenIDConfigurationUrl: https://door.example.com/.well-known/openid-configuration
clientId: <client-id>
clientSecret: <client-secret>
userNameField: name
fullNameFieldName: displayName
emailFieldName: email
groupsFieldName: groups
logoutFromOpenidProvider: true
properties:
- "pkce"
O plugin apenas passa os grupos para o Jenkins. Os direitos vêm da estratégia de autorização: com segurança baseada em Matrix, cada linha da tabela é um usuário ou um grupo, então adicione uma linha para devops-admins e dê a ela Overall/Administer. Escolher o plugin como realm de segurança desativa outros métodos de login, então configure a propriedade escapeHatch do plugin (um nome de usuário e secret de fallback) antes de salvar. O Casdoor também tem seu próprio plugin para Jenkins, descrito em Jenkins plugin, mas o plugin OIDC genérico é o que este post assume.
Grafana
O Grafana usa OAuth genérico. Seu callback é /login/generic_oauth. O scopes padrão do Grafana é user:email, então defina explicitamente os escopos OIDC:
[auth.generic_oauth]
enabled = true
name = Casdoor
client_id = <client-id>
client_secret = <client-secret>
scopes = openid profile email
auth_url = https://door.example.com/login/oauth/authorize
token_url = https://door.example.com/api/login/oauth/access_token
api_url = https://door.example.com/api/userinfo
use_pkce = true
groups_attribute_path = groups
role_attribute_path = contains(groups[*], 'devops-admins') && 'Admin' || contains(groups[*], 'devops-users') && 'Editor' || 'Viewer'
role_attribute_strict = true
O Grafana avalia o role_attribute_path primeiro contra o token de ID, depois contra a resposta do userinfo e, por fim, contra o token de acesso. Os resultados válidos são None, Viewer, Editor, Admin e GrafanaAdmin; este último requer allow_assign_grafana_admin = true. O allowed_groups restringe o login aos grupos listados e requer groups_attribute_path. A sincronização de equipes é um recurso do Grafana Enterprise e do Grafana Cloud.
Argo CD
O Argo CD se comunica diretamente com o Casdoor, sem usar seu Dex integrado. O callback do navegador é /auth/callback. argocd login --sso inicia um servidor local na porta 8085 por padrão e usa http://localhost:8085/auth/callback, portanto registre essa URL também.
Defina url e oidc.config (com name, issuer, clientID, clientSecret, requestedScopes) no argocd-cm. O requestedScopes padrão do Argo CD adiciona um escopo groups. O Casdoor não precisa dele, pois o token de ID JWT sempre inclui groups, então nosso guia solicita ["openid", "profile", "email"]. Os grupos são mapeados no argocd-rbac-cm, onde scopes tem como padrão [groups]:
data:
policy.default: role:readonly
policy.csv: |
g, devops-admins, role:admin
O passo a passo completo, incluindo o segredo do cliente no argocd-secret, está no guia Argo CD.
MinIO
O MinIO lê as políticas de uma única claim, definida com claim_name (padrão policy). Ele não faz mapeamento de grupos. O quickstart do Casdoor no MinIO e nosso guia usam a claim tag do Casdoor: coloque um nome de política do MinIO, como readwrite, no campo Tag do usuário, então:
mc admin config set myminio identity_openid \
config_url="https://door.example.com/.well-known/openid-configuration" \
client_id=<client-id> client_secret=<client-secret> claim_name="tag"
role_policy é a alternativa: todo usuário que fizer login através deste provedor receberá as políticas listadas, e ela não pode ser combinada com claim_name. O callback do Console é <console-url>/oauth_callback. Atrás de um proxy, defina MINIO_BROWSER_REDIRECT_URL; a chave antiga redirect_uri está obsoleta. Observe que o repositório GitHub minio/minio foi arquivado e seu README afirma que não é mais mantido, então verifique qual build do MinIO você executa antes de depender dessas configurações.
Portainer
O Portainer usa um provedor OAuth Personalizado. Preencha Authorization URL (/login/oauth/authorize), Access token URL (/api/login/oauth/access_token) e Resource URL (/api/userinfo) em seu host Casdoor, e defina Redirect URL para a URL base do Portainer. Há também um campo Logout URL. No Portainer CE, Automatic team membership é marcado como um recurso da Business Edition, e a configuração que atribui direitos de administrador a grupos existe apenas na Business Edition. Na CE, usuários criados pelo provisionamento automático recebem a função de usuário padrão e você promove administradores manualmente.
Harbor e GitLab
O Harbor exibe sua URI de redirecionamento na parte inferior da página de configurações OIDC: <harbor-url>/c/oidc/callback. Defina OIDC Provider Endpoint como a URL do Casdoor, Group Claim Name como groups e OIDC Admin Group como devops-admins. O Harbor lê a claim de grupo do token de ID, fornecida pelo formato JWT. Você só pode alternar o Harbor da autenticação por banco de dados para OIDC antes que existam usuários locais.
A documentação OIDC do GitLab possui uma seção sobre o Casdoor e exige que o Casdoor seja servido via HTTPS. O callback é /users/auth/openid_connect/callback. Funções baseadas em grupos (groups_attribute, admin_groups, required_groups, external_groups) exigem GitLab Premium ou Ultimate.
Ferramentas sem OIDC
Para dashboards internos que não possuem login próprio, coloque-os atrás do plugin openid-connect do Apache APISIX (discovery, client_id, client_secret, redirect_uri, bearer_only), conforme o guia do APISIX, ou atrás do nginx conforme descrito em Autenticação SSO com Nginx.
Uma aplicação por ferramenta ou uma compartilhada
Uma única aplicação Casdoor com os callbacks de todas as ferramentas em suas Redirect URLs funciona, mas uma aplicação por ferramenta é mais fácil de gerenciar:
- Cada ferramenta tem seu próprio segredo de cliente, então um segredo vazado do Jenkins não expõe o Grafana.
- Token group format, Token format e a expiração do token são específicos da aplicação, então você pode dar ao Argo CD
Name (group)sem alterar as claims de outra ferramenta. - O Casdoor verifica
post_logout_redirect_uricontra as Redirect URLs da aplicação, então cada lista permanece curta e específica.
Os usuários ainda fazem login apenas uma vez: após o primeiro login, o cookie de sessão do Casdoor permite que o redirecionamento para a próxima ferramenta seja concluído sem solicitar senha.
Sair
O endpoint de encerramento de sessão do Casdoor é /api/logout, listado como end_session_endpoint no documento de descoberta. Ele aceita id_token_hint, post_logout_redirect_uri, client_id e state, e só redireciona para uma URL listada nas Redirect URLs da aplicação. Fazer logout do Casdoor termina a sessão do Casdoor e os tokens daquela sessão, mas cada ferramenta também mantém seu próprio cookie de sessão. Configure o logout em cada ferramenta:
- Jenkins:
logoutFromOpenidProvider, com/OicLogoutregistrado. - Grafana:
signout_redirect_url. - Argo CD:
logoutURLemoidc.config, por exemplohttps://door.example.com/api/logout?id_token_hint={{token}}&post_logout_redirect_uri={{logoutRedirectURL}}. - Harbor: OIDC Session Logout.
- Portainer: Logout URL.
Os detalhes do endpoint estão em RP-initiated logout.
Referências
- Gitea: Authentication,
admin auth add-oauth - Jenkins: OpenId Connect Authentication plugin, configuration reference, Managing security
- Grafana: Configure generic OAuth2 authentication
- Argo CD: User management, RBAC,
argocd login - MinIO: Casdoor quickstart in the MinIO repository
- Portainer: Autenticação OAuth
- Harbor: Configurar autenticação do provedor OIDC
- GitLab: Usar OpenID Connect como um provedor de autenticação
- Apache APISIX: plugin openid-connect