AWS Security Token Serviceを使ってみる
AWS SDKやAWSコマンドラインツールを使う場合、Security Credentialsが必要になります。Security Credentialsの中にはアクセスキーとシークレットアクセスキーが含まれています。AWSのサービスやリソースをAPIを使って管理するときには、この2つのキーを使って認証します。
この2つのキーをどうやって保管するか?が本記事の目標とするところです。
2つのキーをソースコードやもしくはテキストファイル、DB等に格納して使うこともできますが、これだとキーの置き換えをするのが大変です。そこでAWSから提供されているSecurity Token Serviceというサービスを使って、キーの管理を安全に、かつ効率的に行うことを試してみました。
Security Token Serviceとは?
一時的な、かつ制限された特権を持つAWSアカウント、またはIAMユーザのCredential情報を取得可能にする機能です。Security Token Serviceは、以下の3つのアクションが可能です。
- AssumeRole
- IAM Roleの権限を一時的に取得可能。AssumeRoleを実行する時にはIAMのCredentialを使って呼び出す必要あり。AWS親アカウントでは呼び出せないらしい。
- GetFederationToken
- IAMユーザにfederatedされた権限を一時的に取得可能。リクエスト内でユーザ名とポリシーを指定する。
- GetSessionToken
- AWSアカウントまたはIAMユーザの権限を一時的に取得可能。
AWS SDKでSecurity Token Serviceより権限を取得できる。対応しているSDKは2013/04/16時点では以下。
http://docs.aws.amazon.com/STS/latest/UsingSTS/AccessingSTS.html
AWS SDK for Javaを使って、GetSessionTokenした例が以下。今回は取得した権限でS3のバケットリストを表示させている。
import java.io.IOException; import java.util.List; import com.amazonaws.AmazonWebServiceClient; import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.auth.BasicSessionCredentials; import com.amazonaws.auth.PropertiesCredentials; import com.amazonaws.services.s3.AmazonS3Client; import com.amazonaws.services.s3.model.Bucket; import com.amazonaws.services.s3.model.ObjectListing; import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClient; import com.amazonaws.services.securitytoken.model.Credentials; import com.amazonaws.services.securitytoken.model.GetSessionTokenRequest; import com.amazonaws.services.securitytoken.model.GetSessionTokenResult; public class MySecurityTokenSample { public static void main(String[] args) throws IOException { //STSからトークンを取得するために必要なCredential情報 AWSCredentials credentials = new PropertiesCredentials( MySecurityTokenSample.class.getResourceAsStream("AwsCredentials.properties")); //SecurityTokenServiceClientの設定 AWSSecurityTokenServiceClient sts = new AWSSecurityTokenServiceClient(credentials); GetSessionTokenRequest req = new GetSessionTokenRequest(); GetSessionTokenResult res = sts.getSessionToken(req); Credentials tmpCredentials = res.getCredentials(); String accessKeyId = tmpCredentials.getAccessKeyId(); String secretAccessKeyId = tmpCredentials.getSecretAccessKey(); //取得したアクセスキー、シークレットアクセスキーでS3のバケットリストを表示してみる。 BasicSessionCredentials c = new BasicSessionCredentials(tmpCredentials.getAccessKeyId(), tmpCredentials.getSecretAccessKey(), tmpCredentials.getSessionToken()); AmazonS3Client s3Client = new AmazonS3Client(c); s3Client.setEndpoint("s3-ap-northeast-1.amazonaws.com"); List<Bucket> list = s3Client.listBuckets(); for(Bucket b : list) { System.out.println(b.getName()); } } }
こちらを実行すると、バケット名のリストが表示された。
トークンを取得するためには、やはりSecurity Credentialsの情報が必要。なので、システムの中に1台だけトークン管理サーバなるものを立てて、そこの中では唯一Credentials情報を持つ。他のサーバで一時的にCredentials情報が必要な場合は、このサーバが何かしらの安全な方法で配ってあげる形が良さそう。取得したトークンは、デフォルトで12時間まで有効。その時間が過ぎると無効になる。以下のように実行することで、その時間も変更できる。
getSessionTokenRequest.setDurationSeconds(7200);
上記例では、AWSアカウントの権限を取得していたが、以下のようにgetFederatedTokenを使って指定したIAM Userの権限を取得もできる。
import java.io.IOException; import java.util.List; import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.auth.BasicSessionCredentials; import com.amazonaws.auth.PropertiesCredentials; import com.amazonaws.services.s3.AmazonS3Client; import com.amazonaws.services.s3.model.Bucket; import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClient; import com.amazonaws.services.securitytoken.model.Credentials; import com.amazonaws.services.securitytoken.model.GetFederationTokenRequest; import com.amazonaws.services.securitytoken.model.GetFederationTokenResult; import com.amazonaws.services.securitytoken.model.GetSessionTokenRequest; import com.amazonaws.services.securitytoken.model.GetSessionTokenResult; public class MySecurityTokenSample2 { public static void main(String[] args) throws IOException { //STSからトークンを取得するために必要なCredential情報 AWSCredentials credentials = new PropertiesCredentials( MySecurityTokenSample.class.getResourceAsStream("AwsCredentials.properties")); //SecurityTokenServiceClientの設定 AWSSecurityTokenServiceClient sts = new AWSSecurityTokenServiceClient(credentials); GetFederationTokenRequest req = new GetFederationTokenRequest(); req.setName("TVMUser1"); req.setPolicy("{\"Statement\": [{\"Effect\": \"Allow\",\"Action\": \"s3:*\",\"Resource\": \"*\"}]}"); GetFederationTokenResult res = sts.getFederationToken(req); Credentials tmpCredentials = res.getCredentials(); //取得したアクセスキー、シークレットアクセスキーでS3のバケットリストを表示してみる。 BasicSessionCredentials c = new BasicSessionCredentials(tmpCredentials.getAccessKeyId(), tmpCredentials.getSecretAccessKey(), tmpCredentials.getSessionToken()); AmazonS3Client s3Client = new AmazonS3Client(c); s3Client.setEndpoint("s3-ap-northeast-1.amazonaws.com"); List<Bucket> list = s3Client.listBuckets(); for(Bucket b : list) { System.out.println(b.getName()); } } }
TVMUser1というIAM Userで、S3のみにアクセス可能なポリシーをJSONで書いたものを使ってGetFederationTokenしている。
req.setPolicyでは以下のJSONデータを引数に入れている。
{ "Statement": [ { "Effect": "Allow", "Action": "s3:*", "Resource": "*" } ] }
このように、Security Token Serviceを使えば、一時的なCredentials情報を取得できることがわかった!
リンク
- http://docs.aws.amazon.com/AmazonS3/latest/dev/AuthUsingTempFederationTokenJava.html
- http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/securitytoken/AWSSecurityTokenServiceClient.html
- http://docs.aws.amazon.com/general/latest/gr/rande.html#sts_region
- http://docs.aws.amazon.com/STS/latest/UsingSTS/STSMgmtConsole.html