如何在AWS Lambda中运行Terraform?权限报错排查与修复
问题描述
我找到一个旧的GitHub仓库,原本完全匹配我的使用场景,但因为Lambda和Python版本更新,原有代码已无法运行。现在在本地和AWS Lambda环境中执行terraform --version时,都持续遇到PermissionError: [Errno 13] Permission denied: '/tmp/tmpg4l5twh9/terraform'错误。
以下是我编写的用于更新Lambda函数的沙盒代码:
import os import subprocess import urllib.request import tarfile import json import tempfile # Fetch the latest version of Terraform URL = 'https://api.github.com/repos/hashicorp/terraform/releases/latest' with urllib.request.urlopen(URL) as response: data = response.read() encoding = response.info().get_content_charset('utf-8') TERRAFORM_DOWNLOAD_URL = json.loads(data.decode(encoding))['tarball_url'] # Download and extract the latest version of Terraform with tempfile.TemporaryDirectory() as tmpdir: TERRAFORM_TAR_PATH = os.path.join(tmpdir, 'terraform.tar.gz') TERRAFORM_PATH = os.path.join(tmpdir, 'terraform') urllib.request.urlretrieve(TERRAFORM_DOWNLOAD_URL, TERRAFORM_TAR_PATH) with tarfile.open(TERRAFORM_TAR_PATH, "r:gz") as tf: print(f"Extracting {TERRAFORM_TAR_PATH} to {TERRAFORM_PATH}") tf.extractall(path=tmpdir) # Remove the tar file after it's extracted os.remove(TERRAFORM_TAR_PATH) print(f"All files extracted to {TERRAFORM_PATH}") print(f"{TERRAFORM_PATH} contents: {os.listdir(tmpdir)}") # Add Terraform to PATH os.rename(f'{tmpdir}/{os.listdir(tmpdir)[0]}', TERRAFORM_PATH) os.environ["PATH"] += os.pathsep + TERRAFORM_PATH os.chmod(TERRAFORM_PATH, 0o777) # os.system(f'chmod -R 777 {TERRAFORM_PATH}') print(os.listdir(TERRAFORM_PATH)) subprocess.check_output([TERRAFORM_PATH, "--version"])
我认为这不是重复问题,因为我是基于一个曾正常运行的方案进行改造。
解决方案
你的代码存在几个核心问题导致权限错误,逐一修正如下:
1. 下载源错误
你当前拉取的是GitHub仓库的源码压缩包(tarball_url),而非Terraform官方预编译的可执行二进制包。源码包中没有直接可用的terraform执行文件,这是权限错误的根源之一。
2. 权限设置对象错误
你给重命名后的目录设置了777权限,但真正需要执行权限的是目录内的terraform二进制文件,而非目录本身。
修正后的完整代码
import os import subprocess import urllib.request import tarfile import json import tempfile # 获取Terraform最新版本的二进制包地址 URL = 'https://api.github.com/repos/hashicorp/terraform/releases/latest' with urllib.request.urlopen(URL) as response: data = response.read() encoding = response.info().get_content_charset('utf-8') release_data = json.loads(data.decode(encoding)) # 匹配Lambda运行环境(Linux x86_64)的二进制包 for asset in release_data['assets']: if asset['name'].endswith('linux_amd64.zip'): TERRAFORM_DOWNLOAD_URL = asset['browser_download_url'] break # 下载并解压Terraform二进制文件 with tempfile.TemporaryDirectory() as tmpdir: TERRAFORM_ZIP_PATH = os.path.join(tmpdir, 'terraform.zip') TERRAFORM_BIN_PATH = os.path.join(tmpdir, 'terraform') urllib.request.urlretrieve(TERRAFORM_DOWNLOAD_URL, TERRAFORM_ZIP_PATH) # Terraform官方二进制包为zip格式,切换解压模式 with tarfile.open(TERRAFORM_ZIP_PATH, "r:zip") as tf: tf.extract('terraform', path=tmpdir) os.remove(TERRAFORM_ZIP_PATH) # 给二进制文件添加执行权限(0o755足够,无需过度开放777) os.chmod(TERRAFORM_BIN_PATH, 0o755) # 直接调用二进制文件验证版本 result = subprocess.check_output([TERRAFORM_BIN_PATH, "--version"]) print(result.decode('utf-8'))
关键修正说明
- 替换下载源:从源码包改为匹配Lambda运行环境的预编译二进制zip包,确保获取到可执行文件。
- 修正解压格式:Terraform官方发布的二进制包为zip格式,而非tar.gz,因此调整解压模式为
r:zip。 - 精准设置权限:仅给
terraform二进制文件添加执行权限,避免不必要的权限开放。 - 直接调用执行:不再依赖PATH环境变量,直接指定二进制文件路径执行,规避路径配置问题。
Lambda的/tmp目录本身具备读写权限,只要确保解压后的二进制文件拥有执行权限,即可解决权限错误问题。
内容的提问来源于stack exchange,提问作者John R
相关产品推荐
相关产品推荐

