GitHub Actions+Terraform+GCP:Runner权限与服务账号集成问题
背景
我正在用GitHub Actions搭建CI/CD流水线,已通过Terraform完成GCP基础设施部署,使用以下Action完成GCP认证:
- id: 'auth' name: 'Authenticate to Google Cloud' uses: 'google-github-actions/auth@v1' with: service_account: 'my-service-account@my-project.iam.gserviceaccount.com'
当前计划通过Terraform的local_file资源自动生成Ansible清单文件,配置如下:
resource "local_file" "hosts_cfg" { content = templatefile("${path.module}/templates/hosts.tpl", { target_hosts = module.target_hosts.external_ips } ) filename = "/etc/ansible/hosts" }
执行terraform apply时出现权限错误:
│ Error: Create local file error │ │ with local_file.hosts_cfg, │ on main.tf line 183, in resource "local_file" "hosts_cfg": │ 183: resource "local_file" "hosts_cfg" { │ │ An unexpected error occurred while writing the file │ │ +Original Error: open /etc/ansible/hosts: permission denied ╵ Error: Process completed with exit code 1.
改用sudo terraform apply后,又出现GCP认证错误:
╷ │ Error: storage.NewClient() failed: dialing: google: could not find default credentials. See https://developers.google.com/accounts/docs/application-default-credentials for more information. │ │ ╵ Error: Process completed with exit code 1.
疑问解答
1. 用google-github-actions/auth@v1认证后,为什么还是没法在/etc/目录创建文件?
google-github-actions/auth仅负责给Runner进程赋予GCP服务账号的云操作权限,这和Runner本身的系统权限是完全独立的两个概念。GitHub Runner默认以普通系统用户(比如Ubuntu runner中的runner用户)身份运行,而/etc/是系统级保护目录,普通用户没有写入权限,因此无论GCP认证是否成功,都无法直接写入该目录。
2. 用sudo为什么反而丢了GCP凭证?
sudo会切换到root用户的独立环境,而google-github-actions/auth是将GCP凭证注入到当前普通用户的环境变量或默认凭证路径中。切换到root后,这些环境变量不会被自动继承,且root用户的默认凭证路径与普通用户不同,导致Terraform无法找到GCP凭证,进而无法访问状态存储桶。
3. GitHub Runner的权限和Terraform用的服务账号权限是什么关系?
两者是完全独立的权限体系:
- GitHub Runner的权限:指Runner进程在宿主机器上的系统操作权限(如读写文件、执行命令),由运行Runner的操作系统用户身份决定。
- Terraform服务账号权限:指Terraform操作GCP资源时的云服务权限,由GCP服务账号绑定的IAM角色决定。
GCP服务账号权限无法干预Runner的系统操作,Runner的系统权限也不影响GCP资源的访问(只要凭证有效)。
4. 怎么让Runner既能写系统目录,又能正常用GCP服务账号权限?
有两种可行方案:
方案1:拆分Terraform输出与文件复制
不要让Terraform直接写入/etc/ansible/hosts,改为输出到Runner有权限的目录(如当前工作目录),之后单独用sudo cp命令将文件复制到系统目录。这样Terraform无需sudo,GCP凭证可正常使用:- 修改Terraform配置:
resource "local_file" "hosts_cfg" { content = templatefile("${path.module}/templates/hosts.tpl", { target_hosts = module.target_hosts.external_ips } ) filename = "${path.module}/ansible_hosts" } - 在GitHub Actions中添加复制步骤:
- name: Copy Ansible hosts file to system directory run: sudo cp ./ansible_hosts /etc/ansible/hosts
- 修改Terraform配置:
方案2:用sudo传递环境变量
如果必须让Terraform直接写入系统目录,可使用sudo -E terraform apply命令,-E参数会保留当前用户的环境变量,GCP凭证相关的环境变量(如GOOGLE_APPLICATION_CREDENTIALS)会被传递给root用户,Terraform就能找到凭证。但需注意,root环境下运行Terraform可能带来额外安全风险。
内容的提问来源于stack exchange,提问作者SkogensKonung

