セキュリティ責任者としての新しい役割として、私には認証情報と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の認証情報を生成することができます。これは今後のブログのトピックとして取り上げることにします。