React应用如何从流水线变量获取环境配置,避免.env暴露密钥?
我有一个React应用,其package.json的scripts配置如下:
"scripts": { "start": "react-scripts start", "start:int": "env-cmd -f .env.int npm start", "start:ua": "env-cmd -f .env.ua npm start", "build": "react-scripts build", "build:int": "env-cmd -f .env.int npm run-script build", "build:ua": "env-cmd -f .env.ua npm run-script build", "test": "react-scripts test", "eject": "react-scripts eject" }
同时存在.env.int和.env.ua两个环境配置文件,内容分别为:
.env.int:
REACT_APP_AAD_UI_APP_CLIENT_ID= xxx REACT_APP_AAD_API_APP_CLIENT_ID= yyy REACT_APP_AAD_APP_TENANT_ID= aaa REACT_APP_AAD_APP_SERVICE_BASE_URI= abc.com
.env.ua:
REACT_APP_AAD_UI_APP_CLIENT_ID= mmm REACT_APP_AAD_API_APP_CLIENT_ID= nnn REACT_APP_AAD_APP_TENANT_ID= bbb REACT_APP_AAD_APP_SERVICE_BASE_URI= def.com
当前使用以下YAML任务部署静态Web应用:
- task: AzureStaticWebApp@0 name: DeployStaticWebApp displayName: Deploy Static Web App inputs: app_location: 'web-app' app_build_command: 'npm ci && npm run build:int' cwd: '${{ parameters.root }}/webapp_package' azure_static_web_apps_api_token: $(deployment_token) # captured from deploymentOutputs
请问是否可以不在.env文件中配置这些敏感值,转而从流水线变量或其他安全位置获取对应环境配置,以避免密钥公开暴露?
React在构建时会自动注入所有以REACT_APP_开头的环境变量,完全不需要依赖本地的.env文件传递配置。你可以直接通过流水线的安全存储(比如变量组、保密变量)传递敏感值,具体步骤如下:
1. 调整package.json的构建脚本
去掉依赖env-cmd的构建命令,直接使用原生的react-scripts build,环境变量会从流水线传入:
"scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }
如果本地开发需要区分环境,可以保留start:int之类的命令,但指向不提交到仓库的.env.local文件(加入.gitignore),避免敏感值泄露。
2. 在流水线中配置安全变量
在Azure DevOps中,把敏感值存入变量组并标记为保密,或者直接在流水线任务中定义保密变量。比如创建int-env-vars和ua-env-vars两个变量组,分别存储对应环境的配置值。
3. 修改流水线YAML任务,注入环境变量
可以通过两种方式在构建时注入环境变量:
方式一:用任务的env字段传递(更清晰)
- task: AzureStaticWebApp@0 name: DeployStaticWebApp displayName: Deploy Static Web App inputs: app_location: 'web-app' app_build_command: 'npm ci && react-scripts build' cwd: '${{ parameters.root }}/webapp_package' azure_static_web_apps_api_token: $(deployment_token) env: REACT_APP_AAD_UI_APP_CLIENT_ID: $(INT_AAD_UI_CLIENT_ID) REACT_APP_AAD_API_APP_CLIENT_ID: $(INT_AAD_API_CLIENT_ID) REACT_APP_AAD_APP_TENANT_ID: $(INT_AAD_TENANT_ID) REACT_APP_AAD_APP_SERVICE_BASE_URI: $(INT_SERVICE_BASE_URI)
这里的$(INT_xxx)是你在流水线变量组中定义的保密变量。
方式二:直接在构建命令中注入
- task: AzureStaticWebApp@0 name: DeployStaticWebApp displayName: Deploy Static Web App inputs: app_location: 'web-app' app_build_command: 'npm ci && REACT_APP_AAD_UI_APP_CLIENT_ID=$(INT_AAD_UI_CLIENT_ID) REACT_APP_AAD_API_APP_CLIENT_ID=$(INT_AAD_API_CLIENT_ID) REACT_APP_AAD_APP_TENANT_ID=$(INT_AAD_TENANT_ID) REACT_APP_AAD_APP_SERVICE_BASE_URI=$(INT_SERVICE_BASE_URI) react-scripts build' cwd: '${{ parameters.root }}/webapp_package' azure_static_web_apps_api_token: $(deployment_token)
4. 区分不同环境部署
如果需要部署int和ua两个环境,可以创建不同的流水线阶段,分别引用对应的变量组。比如int阶段引用int-env-vars,ua阶段引用ua-env-vars,再各自注入对应环境变量即可。
这种方式的核心优势是:敏感值不会出现在代码仓库中,仅存储在流水线的安全存储系统里,只有授权人员可以查看和修改,从根源上避免了密钥公开暴露的风险。
内容的提问来源于stack exchange,提问作者user989988

