diff --git a/pom.xml b/pom.xml index 1ff721eb..b1f2c302 100644 --- a/pom.xml +++ b/pom.xml @@ -112,6 +112,17 @@ + + com.amazonaws + aws-java-sdk-sts + ${aws-java-sdk.version} + + + commons-logging + commons-logging + + + com.amazonaws amazon-kinesis-client diff --git a/src/main/java/org/graylog/aws/auth/AWSAuthProvider.java b/src/main/java/org/graylog/aws/auth/AWSAuthProvider.java index af51b73f..0e608fb5 100644 --- a/src/main/java/org/graylog/aws/auth/AWSAuthProvider.java +++ b/src/main/java/org/graylog/aws/auth/AWSAuthProvider.java @@ -6,6 +6,10 @@ import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.auth.STSAssumeRoleSessionCredentialsProvider; +import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder; +import com.amazonaws.services.securitytoken.AWSSecurityTokenService; +import com.amazonaws.services.securitytoken.model.GetCallerIdentityRequest; import org.graylog.aws.config.AWSPluginConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,20 +24,53 @@ public class AWSAuthProvider implements AWSCredentialsProvider { private AWSCredentialsProvider credentials; public AWSAuthProvider(AWSPluginConfiguration config) { - this(config, null, null); + this(config, null, null, null,null); } - public AWSAuthProvider(AWSPluginConfiguration config, @Nullable String accessKey, @Nullable String secretKey) { + public AWSAuthProvider(AWSPluginConfiguration config, + @Nullable String accessKey, + @Nullable String secretKey, + @Nullable String region, + @Nullable String assumeRoleArn) { + this.credentials = this.resolveAuthentication(config, accessKey, secretKey, region, assumeRoleArn); + } + + private AWSCredentialsProvider resolveAuthentication(AWSPluginConfiguration config, + @Nullable String accessKey, + @Nullable String secretKey, + @Nullable String region, + @Nullable String assumeRoleArn) { + AWSCredentialsProvider awsCredentials; if (!isNullOrEmpty(accessKey) && !isNullOrEmpty(secretKey)) { - this.credentials = new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey, secretKey)); + awsCredentials = new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey, secretKey)); LOG.debug("Using input specific config"); } else if (!isNullOrEmpty(config.accessKey()) && !isNullOrEmpty(config.secretKey())) { - this.credentials = new AWSStaticCredentialsProvider(new BasicAWSCredentials(config.accessKey(), config.secretKey())); + awsCredentials = new AWSStaticCredentialsProvider(new BasicAWSCredentials(config.accessKey(), config.secretKey())); LOG.debug("Using AWS Plugin config"); } else { - this.credentials = new DefaultAWSCredentialsProviderChain(); + awsCredentials = new DefaultAWSCredentialsProviderChain(); LOG.debug("Using Default Provider Chain"); } + if (!isNullOrEmpty(assumeRoleArn) && !isNullOrEmpty(region)) { + LOG.debug("Creating cross account assume role credentials"); + return this.getSTSCredentialsProvider(awsCredentials, region, assumeRoleArn); + } else { + return awsCredentials; + } + } + + private AWSCredentialsProvider getSTSCredentialsProvider(AWSCredentialsProvider awsCredentials, String region, String assumeRoleArn) { + AWSSecurityTokenService stsClient = AWSSecurityTokenServiceClientBuilder.standard() + .withRegion(region) + .withCredentials(awsCredentials) + .build(); + String roleSessionName = String.format("API_KEY_%s@ACCOUNT_%s", + awsCredentials.getCredentials().getAWSAccessKeyId(), + stsClient.getCallerIdentity(new GetCallerIdentityRequest()).getAccount()); + LOG.debug("Cross account role session name: " + roleSessionName); + return new STSAssumeRoleSessionCredentialsProvider.Builder(assumeRoleArn, roleSessionName) + .withStsClient(stsClient) + .build(); } @Override diff --git a/src/main/java/org/graylog/aws/inputs/cloudtrail/CloudTrailTransport.java b/src/main/java/org/graylog/aws/inputs/cloudtrail/CloudTrailTransport.java index e52a0cbf..0d520231 100644 --- a/src/main/java/org/graylog/aws/inputs/cloudtrail/CloudTrailTransport.java +++ b/src/main/java/org/graylog/aws/inputs/cloudtrail/CloudTrailTransport.java @@ -48,6 +48,7 @@ public class CloudTrailTransport extends ThrottleableTransport { private static final String CK_SQS_NAME = "aws_sqs_queue_name"; private static final String CK_ACCESS_KEY = "aws_access_key"; private static final String CK_SECRET_KEY = "aws_secret_key"; + private static final String CK_ASSUME_ROLE_ARN = "aws_assume_role_arn"; private static final Regions DEFAULT_REGION = Regions.US_EAST_1; @@ -118,7 +119,9 @@ public void doLaunch(MessageInput input) throws MisfireException { final AWSAuthProvider authProvider = new AWSAuthProvider( config, input.getConfiguration().getString(CK_ACCESS_KEY), - input.getConfiguration().getString(CK_SECRET_KEY) + input.getConfiguration().getString(CK_SECRET_KEY), + input.getConfiguration().getString(CK_AWS_SQS_REGION), + input.getConfiguration().getString(CK_ASSUME_ROLE_ARN) ); subscriber = new CloudTrailSubscriber( @@ -208,6 +211,14 @@ public ConfigurationRequest getRequestedConfiguration() { TextField.Attribute.IS_PASSWORD )); + r.addField(new TextField( + CK_ASSUME_ROLE_ARN, + "AWS assume role ARN", + "", + "The role ARN with required permissions (cross account access)", + ConfigurationField.Optional.OPTIONAL + )); + return r; } } diff --git a/src/main/java/org/graylog/aws/inputs/transports/KinesisTransport.java b/src/main/java/org/graylog/aws/inputs/transports/KinesisTransport.java index 4667bdfc..5a06ae34 100644 --- a/src/main/java/org/graylog/aws/inputs/transports/KinesisTransport.java +++ b/src/main/java/org/graylog/aws/inputs/transports/KinesisTransport.java @@ -42,6 +42,7 @@ public class KinesisTransport implements Transport { private static final String CK_AWS_REGION = "aws_region"; private static final String CK_ACCESS_KEY = "aws_access_key"; private static final String CK_SECRET_KEY = "aws_secret_key"; + private static final String CK_ASSUME_ROLE_ARN = "aws_assume_role_arn"; private static final String CK_KINESIS_STREAM_NAME = "kinesis_stream_name"; private final Configuration configuration; @@ -75,7 +76,12 @@ public void launch(MessageInput input) throws MisfireException { final AWSPluginConfiguration awsConfig = clusterConfigService.getOrDefault(AWSPluginConfiguration.class, AWSPluginConfiguration.createDefault()); - AWSAuthProvider authProvider = new AWSAuthProvider(awsConfig, configuration.getString(CK_ACCESS_KEY), configuration.getString(CK_SECRET_KEY)); + AWSAuthProvider authProvider = new AWSAuthProvider( + awsConfig, configuration.getString(CK_ACCESS_KEY), + configuration.getString(CK_SECRET_KEY), + configuration.getString(CK_AWS_REGION), + configuration.getString(CK_ASSUME_ROLE_ARN) + ); this.reader = new KinesisConsumer( configuration.getString(CK_KINESIS_STREAM_NAME), @@ -159,6 +165,14 @@ public ConfigurationRequest getRequestedConfiguration() { TextField.Attribute.IS_PASSWORD )); + r.addField(new TextField( + CK_ASSUME_ROLE_ARN, + "AWS assume role ARN", + "", + "Role ARN with required permissions (cross account access)", + ConfigurationField.Optional.OPTIONAL + )); + r.addField(new TextField( CK_KINESIS_STREAM_NAME, "Kinesis Stream name",