Como disse @Connor McCarthy, enquanto esperávamos que a Amazon apresentasse uma solução melhor para chaves permanentes, nesse meio tempo nós precisaríamos gerar as chaves do servidor Jenkins de alguma forma.
Minha solução é ter um job periódico que atualize as credenciais do Jenkins para o ECR a cada 12 horas automaticamente, usando a API do Groovy. Isto é baseado em esta resposta muito detalhada , embora eu tenha feito algumas coisas de forma diferente e eu teve que modificar o script.
Etapas:
- Verifique se seu mestre do Jenkins pode acessar a API da AWS necessária. Na minha configuração, o mestre do Jenkins está sendo executado no EC2 com uma função do IAM, portanto, precisei adicionar a permissão
ecr:GetAuthorizationToken
à função de servidor. [ update ] Para que os pushes sejam concluídos com êxito, você também precisa conceder estas permissões:ecr:InitiateLayerUpload, ecr:UploadLayerPart, ecr:CompleteLayerUpload, ecr:BatchCheckLayerAvailability, ecr:PutImage
. A Amazon tem uma política interna que oferece esses recursos, chamadosAmazonEC2ContainerRegistryPowerUser
. - Verifique se o AWS CLI está instalado no mestre. Na minha configuração, com o mestre executando em um contêiner do Docker do Debian, acabei de adicionar esta etapa de criação do shell ao trabalho de geração de chave:
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
- Instale o plug-in do Groovy que permite executar o script Groovy como parte do sistema Jenkins .
- Na tela de credenciais, procure sua chave ECR do AWS, clique em "Avançado" e registre seu "ID". Para este exemplo, vou assumir que é "12345".
- Crie uma nova tarefa, com um lançamento periódico de 12 horas, e adicione uma etapa de criação "script Groovy do sistema" com o seguinte script:
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)
}
Por favor, note:
- o uso da string codificada
"AWS"
como o nome de usuário das credenciais ECR - é assim que a ECR funciona, mas se você tiver várias credenciais com o nome de usuário "AWS", será necessário atualizar o script para localize as credenciais com base no campo de descrição ou algo assim. - Você deve usar o ID real de sua chave ECR real no script, porque a API para credenciais substitui o objeto de credenciais por um novo objeto em vez de apenas atualizá-lo, e a ligação entre a etapa de compilação do Docker e a chave é o ID. Se você usar o valor
null
para a ID (como na resposta que eu vinculei antes), uma nova ID será criada e a configuração das credenciais na etapa de compilação da janela de encaixe será perdida.
E é isso. O script deve ser executado a cada 12 horas e atualizar as credenciais do ECR, e podemos continuar a usar os plug-ins do Docker.