kingsrule50/azure-static-website-lab
GitHub: kingsrule50/azure-static-website-lab
一个演示如何在 Azure 上通过 Terraform、GitHub Actions 和 OIDC 联邦身份认证实现零密钥安全交付静态网站的实验项目。
Stars: 0 | Forks: 0
# Azure 上的安全静态网站托管 — Terraform + GitHub Actions (OIDC)
我构建了这个实验来演示一个在尽可能小的足迹上运行的、完整的、生产级的交付工作流:Azure Blob Storage 上的静态网站。重点不在于网站本身,而在于流水线。Terraform 负责配置和强化基础设施;GitHub Actions 在每次推送到 `main` 分支时自动部署内容,并通过**不存储任何密钥的 OIDC 联邦身份验证**向 Azure 进行身份验证。
## 架构
```
Developer GitHub Azure
───────── ────── ─────
git push main ──────▶ Actions workflow ──OIDC token──▶ Entra ID (federated credential)
│ │ issues short-lived token
│ ▼
└──── az storage blob ────▶ Storage Account (LRS)
upload-batch └─ $web container
│
Recruiter's browser ◀───── HTTPS / TLS 1.2 ──┘
(static website endpoint)
```
*(替换为渲染后的图表:`docs/architecture.png`)*
## 我的设计思路与原因
- **由 Terraform 管理的基础设施。** 资源组、存储帐户和静态网站配置全部在代码中声明,远程状态存储在我的中央 Terraform 状态存储帐户(`static-website.tfstate`)中——这是我在整个实验系列中使用的相同状态管理模式。
- **默认进行安全强化。** 仅限 HTTPS 流量、最低 TLS 1.2 以及完全禁用匿名 blob 访问——静态网站通过专用的 Web endpoint 提供服务,因此永远不需要公共 blob 访问。
- **零存储凭证。** GitHub Actions 流水线通过 Entra ID 应用注册进行身份验证,该应用注册具有作用域限定于此存储库 `main` 分支的**联合凭证**。没有会泄露、需要轮换或过期的客户端密钥。Azure 在工作流运行时颁发短期 token。
- **最小权限 RBAC。** 流水线身份仅持有 `Storage Blob Data Contributor` 和实验室资源组的 `Reader` 角色——它无法创建、修改或删除基础设施。
- **关注点分离。** Terraform 拥有基础设施生命周期;CI/CD 流水线仅拥有内容。两者都不能执行对方的任务。
## 仓库结构
```
├── terraform/ # Infrastructure as Code (azurerm ~> 4.0)
│ ├── providers.tf # provider + remote state backend
│ ├── main.tf # RG, hardened storage account, static website
│ ├── variables.tf
│ └── outputs.tf # site URL + storage account name
├── site/ # Website content — deployed by CI/CD, not Terraform
│ ├── index.html
│ └── 404.html
├── .github/workflows/
│ └── deploy.yml # OIDC login → upload-batch to $web
├── scripts/
│ └── setup-oidc.sh # one-time app registration + federated credential + RBAC
└── docs/screenshots/ # validation evidence
```
## 部署演练
**1. 配置基础设施**
```
cd terraform
terraform init
terraform plan
terraform apply
terraform output website_url
```
**2. 一次性 OIDC 联邦设置**
```
az login
bash scripts/setup-oidc.sh
```
然后将其输出的四个值添加为 GitHub Actions **变量**(不是 secrets——它们都不敏感):
`AZURE_CLIENT_ID`、`AZURE_TENANT_ID`、`AZURE_SUBSCRIPTION_ID`、`STORAGE_ACCOUNT`。
**3. 部署内容**
```
git add site/ && git commit -m "Update site" && git push
```
## 验证证据
*(截图目标——在录制会话期间捕获)*
1. `terraform apply` 输出,显示已创建的资源 + `website_url` 输出
2. Azure Portal — 存储帐户 **Configuration** 边栏选项卡,显示 *Secure transfer required: Enabled* 和 *Minimum TLS: 1.2*
3. Azure Portal — **Static website** 边栏选项卡,显示已启用状态和主要 endpoint
4. GitHub Actions — 成功的工作流运行,其中 OIDC 登录步骤已展开
5. Entra ID — 应用注册 **Certificates & secrets** 边栏选项卡,显示联合凭证和 **零客户端密钥**
6. 资源组上的 IAM 边栏选项卡,仅显示两个最小权限角色分配
7. 浏览器中的实时站点,可见挂锁/HTTPS 标志
8. 针对直接 blob URL 的失败匿名访问尝试(证明公共访问已被禁用)
## 成本
包含两个 HTML 文件的标准 LRS 存储几乎没有成本(每月不到一美分)。与基于 VM 的实验不同,这个实验会永久运行——上面的实时 URL 始终可用。
## 核心要点
- OIDC 工作负载身份联邦消除了最常见的 CI/CD 安全故障:流水线 secrets 中泄露的长期有效云凭证。
- Blob Storage 上的静态网站托管可以在完全禁用匿名 blob 访问的情况下工作——`$web` 容器通过专用 endpoint 提供服务,这是许多指南都弄错的一个细节。
- 在 azurerm provider v4.x 中,静态网站配置从内联块移到了独立的 `azurerm_storage_account_static_website` 资源。
- 将内容部署排除在 Terraform 之外(没有 `azurerm_storage_blob` 资源)意味着内容更改永远不会触及基础设施状态。
*我的企业 Azure 基础设施自动化作品集中的实验 · [github.com/kingsrule50](https://github.com/kingsrule50)*
标签:Azure, ECS, OIDC, Terraform, 后端开发, 基础设施自动化, 应用安全, 静态网站托管