---
id: cicd-secrets-oidc
title: "Secrets và OIDC"
shortTitle: "Secrets & OIDC"
track: cicd
trackTitle: "CI/CD"
order: 5
level: important
status: published
estimatedMinutes: 35
prerequisites:
  - cicd-azure-pipelines
next: cicd-circleci
reviewedAgainst: 2026-10-12
sources:
  - title: "OpenID Connect in Azure"
    url: https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-azure
  - title: "OpenID Connect reference"
    url: https://docs.github.com/en/actions/reference/security/oidc
---

# Secrets và OIDC

Secret trong CI là giá trị GitHub giấu trong log. OIDC là cách job lấy token ngắn từ Azure mà không cất client secret. Bài này lấy GitHub Actions làm mẫu, vì đó là CI chính của lộ trình.

## Để làm gì

Bạn để `id-token: write` đúng chỗ, và không lưu client secret của app registration khi đã dùng federated credential.

## Gồm những gì

- `permissions` với `id-token: write`.
- `azure/login` nhận client id, tenant id, subscription id.
- Subject của token phải khớp federated credential.

Đừng tạo app registration trên tenant thật, và đừng dán secret vào repo để thử.

## Dùng khi nào

Workflow deploy lên Azure. Mỗi lần chạy, GitHub ký một JWT, Azure đổi JWT đó lấy access token, job dùng xong là hết hạn. Client secret thì nằm trong GitHub cho đến khi ai đó xoay, và dễ bị copy ra log.

Đừng cấp `id-token: write` cho mọi job nếu chỉ job deploy cần. Quyền này không cho workflow ghi resource trên GitHub. Nó cho job xin JWT. Docs của GitHub nói rõ điều đó. Quyền ghi trên Azure nằm ở app registration và role assignment, không nằm ở dòng `write` này.

## Kiến thức cốt lõi

Federated credential trên app registration khai một issuer là GitHub và một subject. Subject dạng phổ biến là `repo:ORG/REPO:ref:refs/heads/main`. Nhánh khác không lấy được token nếu subject chỉ khóa `main`.

Workflow cần:

```yaml
permissions:
  id-token: write
  contents: read
```

Thiếu `id-token: write` thì action không xin được JWT. `contents: read` đủ để checkout nếu không push lại repo.

`azure/login` đổi JWT lấy token Azure. Ba giá trị `client-id`, `tenant-id`, `subscription-id` không phải mật khẩu, cũng không phải client secret. Vẫn để chúng trong secret hoặc variable để khỏi cứng trong YAML. OIDC đã login được thì đừng cấu hình thêm `creds` JSON chứa secret.

Mask của GitHub không phải mã hóa. In secret ra stdout thì log bị che nếu trùng chuỗi đã đăng ký, nhưng vẫn đừng in.

## Lệnh và code mẫu

Không chạy. Đây là job deploy, chỉ review:

```yaml
permissions:
  id-token: write
  contents: read
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
```

Pin action theo SHA khi đưa vào repo thật. `@v2` trong lab đọc cho dễ.

## Thực hành

1. Chỉ dòng nào khiến GitHub chịu phát JWT.
2. Viết subject bạn sẽ khai nếu repo là `org/app` và chỉ nhánh `main` được deploy.
3. Không tạo credential trên Azure trong bài này.

## Kết quả mong đợi

Dòng là `id-token: write`. Subject là `repo:org/app:ref:refs/heads/main`.

## Checklist

- [ ] Job deploy dùng OIDC, không còn JSON client secret trong secret của repo.
- [ ] Federated credential khóa đúng repo và nhánh.
- [ ] `id-token: write` chỉ ở workflow hoặc job cần token.

## Lỗi thường gặp

**Azure báo subject không khớp.** YAML chạy từ pull request nhưng credential chỉ cho `refs/heads/main`. Sửa credential hoặc đừng deploy từ pull request.

**Vẫn để `AZURE_CREDENTIALS` chứa client secret bên cạnh OIDC.** Hai cửa. Xóa secret cũ sau khi OIDC đã login được, không giữ cho chắc.

## Nguồn

1. [Configuring OpenID Connect in Azure](https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-azure) — `azure/login` và quyền token.
2. [OpenID Connect reference](https://docs.github.com/en/actions/reference/security/oidc) — `id-token: write` không phải quyền ghi resource.

## Tiếp theo

[CircleCI](./07-circleci.md)
