セキュリティ責任者としての新しい役割として、私には認証情報とAWSのセキュリティを管理する責任があります。

今日は、「キーローテーション」と呼ばれるAWSセキュリティのベストプラクティスの1つを詳しく見ていきます。この方法では、少なくとも90日おきにキーを更新する必要があります。できるだけ頻繁にキーを更新する必要があるため、データが漏洩したときには認証情報はすでに期限切れになっています。

できるだけ、AWSインスタンスでロールを使用し、APIキーの使用を可能な限り減らすことになります。それにもかかわらず、NuxeoではいくつかのJenkinsがAWSの外にあるため、ラップトップからAWS APIを随時起動することが可能です。

Nuxeoでセキュリティポリシーを実施する前に、私はあらゆる人の立場に立って、誰もが簡単にできるようにしています。上記のシナリオでは、ShellとJenkinsのキーローテーションの両方の解決策を見つけることにしました。

キーの更新自体は簡単なプロセスです。これには以下のステップが含まれています。

1.新しいAWSキーを作成する
2.その新しいAWSキーを格納する
3.古いAWSキーを削除する

AWS CLI

S3オブジェクトの問題が何であるかを理解できるように、コンピュータ上でオブジェクトACLをチェックできれば、素晴らしいですね。

aws --profile=nuxeo s3api get-object-acl --bucket MyBucket --key MyObject

次のような1つのコマンドを使ってアクセスキーを更新することができれば、とてもいいですね。

aws --profile=nuxeo configure rotate-keys

残念ですが、このコマンドはまだ存在しません。Pullリクエストはここで完了し、マージを待っています(おそらく+1を追加すると、マージプロセスが高速になります)

待っている間、もう一つのAWSユーティリティyawsを作りました。

このユーティリティはpipで利用可能です。

pip install yaws

次のように入力して、キーの更新を行うことができます。

yaws --profile=nuxeo rotate-keys

キーは更新されました!引き続きAWSを使用し、crontabエントリを追加するだけで済みます。

0 0 * * * yaws --profile=nuxeo rotate-keys

必要な作業は以上です。こうすることで、1時間に一度キーを自動的に更新することが可能になります。

Jenkins

Jenkinsは、通常、S3バケットにアーティファクトをプッシュするか、Ansibleスクリプトを起動するなど、クラウド上で何らかの操作を行う必要があります。

キーの格納を扱うプラグインaws-credentials-pluginがあり、roleArnを指定した場合はassumeRoleオペレーションもあります。

したがって、基本的に1つのAccessKeyを、さまざまな役割を持つ複数のAWS Jenkins認証情報にマッピングできます。

しかし、これらのAccessKeysを更新し、これらのアクセスキーを使用するすべての認証情報を更新することは依然として必要です。

そのために、次のようにGroovyスクリプトを使用します。

import com.cloudbees.jenkins.plugins.awscredentials.AWSCredentialsImpl;
import com.cloudbees.plugins.credentials.domains.*;

node {
    // Load all the AWSCredentials from Jenkins
    def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
        com.cloudbees.jenkins.plugins.awscredentials.AWSCredentialsImpl.class,
        jenkins.model.Jenkins.instance
    )
    // Create a map of AccessKey to Credentials attached to this accessKeys
    def rotate = [:]
    // Building the map
    creds.each {
        if (!rotate[it.accessKey]) {
            rotate[it.accessKey] = []
        }
        rotate[it.accessKey].add(it)
    }
    // For each accessKey
    rotate.each {
       // Rotate the access key
        accessKey = it.value[0].accessKey
        secret = it.value[0].secretKey.getPlainText()
        withEnv(["AWS_ACCESS_KEY_ID=${accessKey}","AWS_SECRET_ACCESS_KEY=${secret}"]) {
            newKeyRaw = sh(returnStdout: true, script: "${aws_bin} iam create-access-key").trim()
            newKey = readJSON(text: newKeyRaw)
            sh(script: "${aws_bin} iam delete-access-key --access-key-id=${accessKey}")
            println("Rotate key ${accessKey} to ${newKey.AccessKey.AccessKeyId}")
        }
        // Now that the accessKey has been rotated on AWS, we need to update all credentials using it
        def credentials_store = jenkins.model.Jenkins.instance.getExtensionList(
            'com.cloudbees.plugins.credentials.SystemCredentialsProvider'
            )[0].getStore()
        it.value.each {
            cred = it
            domain = null
            // Search domain for this credentials : not optimal
            credentials_store.getDomains().each {
                curDomain = it
                credentials_store.getCredentials(it).each {
                    if (it == cred) {
                        domain = curDomain
                    }
                }
            }
            if (curDomain) {
                newIt = new AWSCredentialsImpl(it.scope, it.id, newKey.AccessKey.AccessKeyId, newKey.AccessKey.SecretAccessKey, it.description, it.iamRoleArn, it.iamMfaSerialNumber)
                credentials_store.updateCredentials(curDomain, it, newIt)
            } else {
                println("WARNING: key ${it.id} (${it.AccessKey} failed to be update with ${newKey.AccessKey.AccessKeyId}")
            }
        }
    }
}

このスクリプトではJenkinsの管理者として、GroovyのサンドボックスでJenkinsを実行しないようにする必要があります。

あと行う必要があるのは、Jenkinsで定期ジョブを作成することだけです!

HashiCorp Vault

今日説明したこと以外にも、HachiCorp Vaultなどの他のアプローチがあり、Throwableの認証情報を生成することができます。これは今後のブログのトピックとして取り上げることにします。