正如@Connor McCarthy所说的那样,在等待亚马逊为更多永久密钥提供更好的解决方案的同时,与此同时,我们需要以某种方式在Jenkins服务器上生成密钥。
我的解决方案是使用Groovy API定期执行一项工作,每12小时自动更新一次ECR的Jenkins凭证。这是基于这个非常详细的答案的,尽管我做了一些不同的事情并且不得不修改脚本。
脚步:
- 确保您的Jenkins管理员可以访问所需的AWS API。在我的设置中,Jenkins主服务器在具有IAM角色的EC2上运行,因此我只需
ecr:GetAuthorizationToken
要向服务器角色添加权限。[ update ]要成功完成任何推送,您还需要授予以下权限:ecr:InitiateLayerUpload, ecr:UploadLayerPart, ecr:CompleteLayerUpload, ecr:BatchCheckLayerAvailability, ecr:PutImage
。Amazon的内置政策提供了这些功能,称为AmazonEC2ContainerRegistryPowerUser
。
- 确保在主服务器上安装了AWS CLI。在我的设置中,将主服务器运行在debian docker容器中,我将此shell构建步骤添加到了密钥生成作业中:
dpkg -l python-pip >/dev/null 2>&1 || sudo apt-get install python-pip -y; pip list 2>/dev/null | grep -q awscli || pip install awscli
- 安装Groovy插件,该插件可让您将Groovy脚本作为Jenkins系统的一部分运行。
- 在凭证屏幕中,查找您的AWS ECR密钥,单击“高级”并记录其“ ID”。对于此示例,我将假定它为“ 12345”。
- 创建一个新工作,定期启动12个小时,并使用以下脚本添加“系统Groovy脚本”构建步骤:
import jenkins.model.*
import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl
def changePassword = { username, new_password ->
def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
com.cloudbees.plugins.credentials.common.StandardUsernameCredentials.class,
Jenkins.instance)
def c = creds.findResult { it.username == username ? it : null }
if ( c ) {
println "found credential ${c.id} for username ${c.username}"
def credentials_store = Jenkins.instance.getExtensionList(
'com.cloudbees.plugins.credentials.SystemCredentialsProvider'
)[0].getStore()
def result = credentials_store.updateCredentials(
com.cloudbees.plugins.credentials.domains.Domain.global(),
c,
new UsernamePasswordCredentialsImpl(c.scope, "12345", c.description, c.username, new_password))
if (result) {
println "password changed for ${username}"
} else {
println "failed to change password for ${username}"
}
} else {
println "could not find credential for ${username}"
}
}
println "calling AWS for docker login"
def prs = "/usr/local/bin/aws --region us-east-1 ecr get-login".execute()
prs.waitFor()
def logintext = prs.text
if (prs.exitValue()) {
println "Got error from aws cli"
throw new Exception()
} else {
def password = logintext.split(" ")[5]
println "Updating password"
changePassword('AWS', password)
}
请注意:
- 使用硬编码的字符串
"AWS"
作为ECR凭据的用户名-这是ECR的工作方式,但是如果您有多个带有用户名“ AWS”的凭据,则需要更新脚本以基于说明字段或其他内容。
- 您必须在脚本中使用真实的ECR密钥的真实ID,因为凭证的API用新对象代替了凭证对象,而不仅仅是更新了它,并且Docker构建步骤和密钥之间的绑定是通过ID。如果您使用
null
ID 的值(如我之前链接的答案),那么将创建一个新的ID,并且docker build步骤中的凭据设置将丢失。
就是这样-该脚本应该能够每12小时运行一次并刷新ECR凭据,并且我们可以继续使用Docker插件。