Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add API request to get permissions #196

Merged
merged 5 commits into from
Aug 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.graylog.integrations.aws.resources.requests.KinesisHealthCheckRequest;
import org.graylog.integrations.aws.resources.responses.AvailableServiceResponse;
import org.graylog.integrations.aws.resources.responses.KinesisHealthCheckResponse;
import org.graylog.integrations.aws.resources.responses.KinesisPermissionsResponse;
import org.graylog.integrations.aws.resources.responses.LogGroupsResponse;
import org.graylog.integrations.aws.resources.responses.RegionsResponse;
import org.graylog.integrations.aws.resources.responses.StreamsResponse;
Expand Down Expand Up @@ -86,6 +87,18 @@ public AvailableServiceResponse getAvailableServices() {
return awsService.getAvailableServices();
}

@GET
@Timed
@Path("/permissions")
@ApiResponses(value = {
@ApiResponse(code = 500, message = AWSService.POLICY_ENCODING_ERROR),
})
@ApiOperation(value = "Get the permissions required for the AWS Kinesis setup and for the Kinesis auto-setup.")
@RequiresPermissions(AWSPermissions.AWS_READ)
public KinesisPermissionsResponse getPermissions() {
return awsService.getPermissions();
}

/**
* Get all available AWS CloudWatch log groups names for the specified region.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public class KinesisSetupResource implements PluginRestResource {

// Enable mocked responses for UI testing.
// TODO: Remove later.
private boolean mockResponses = true;
public boolean mockResponses = true;

@Inject
public KinesisSetupResource(CloudWatchService cloudWatchService, KinesisService kinesisService) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.graylog.integrations.aws.resources.responses;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.auto.value.AutoValue;
import org.graylog.autovalue.WithBeanGetter;

@JsonAutoDetect
@AutoValue
@WithBeanGetter
public abstract class KinesisPermissionsResponse {

private static final String SETUP_POLICY = "setup_policy";
private static final String AUTO_SETUP_POLICY = "auto_setup_policy";

@JsonProperty(SETUP_POLICY)
public abstract String setupPolicy();

@JsonProperty(AUTO_SETUP_POLICY)
public abstract String autoSetupPolicy();

public static KinesisPermissionsResponse create(@JsonProperty(SETUP_POLICY) String setupPolicy,
@JsonProperty(AUTO_SETUP_POLICY) String autoSetupPolicy) {
return new AutoValue_KinesisPermissionsResponse(setupPolicy, autoSetupPolicy);
}
}
98 changes: 73 additions & 25 deletions src/main/java/org/graylog/integrations/aws/service/AWSService.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.graylog.integrations.aws.resources.responses.AWSRegion;
import org.graylog.integrations.aws.resources.responses.AvailableService;
import org.graylog.integrations.aws.resources.responses.AvailableServiceResponse;
import org.graylog.integrations.aws.resources.responses.KinesisPermissionsResponse;
import org.graylog.integrations.aws.resources.responses.RegionsResponse;
import org.graylog.integrations.aws.transports.KinesisTransport;
import org.graylog2.database.NotFoundException;
Expand Down Expand Up @@ -137,9 +138,60 @@ public static StaticCredentialsProvider buildCredentialProvider(String accessKey
* @return A list of available AWS services supported by the AWS Graylog AWS integration.
*/
public AvailableServiceResponse getAvailableServices() {
AWSPolicy awsPolicy = buildAwsSetupPolicy();

// Create an AWSPolicy object that can be serialized into JSON.
// The user will use this as a guide to create a policy in their AWS account.
ArrayList<AvailableService> services = new ArrayList<>();

// Deliberately provide the policy JSON as a string. The UI will format and display this to the user.
String policy;
try {
policy = objectMapper.writeValueAsString(awsPolicy);
} catch (JsonProcessingException e) {
// Return a more general internal server error if JSON encoding fails.
LOG.error(POLICY_ENCODING_ERROR, e);
throw new InternalServerErrorException(POLICY_ENCODING_ERROR, e);
}
AvailableService cloudWatchService =
AvailableService.create("CloudWatch",
"Retrieve CloudWatch logs via Kinesis. Kinesis allows streaming of the logs " +
"in real time. AWS CloudWatch is a monitoring and management service built " +
"for developers, system operators, site reliability engineers (SRE), " +
"and IT managers.",
policy,
"Requires Kinesis",
"https://aws.amazon.com/cloudwatch/");
services.add(cloudWatchService);
return AvailableServiceResponse.create(services, services.size());
}

/**
* @return A list of required permissions for the regular AWS Kinesis setup and for the auto-setup.
*/
public KinesisPermissionsResponse getPermissions() {

final String setupPolicyString = policyAsJsonString(buildAwsSetupPolicy());
final String autoSetupPolicyString = policyAsJsonString(buildAwsAutoSetupPolicy());
return KinesisPermissionsResponse.create(setupPolicyString, autoSetupPolicyString);
}

/**
* Convert the {@link AWSPolicy} object into a JSON string.
* @return A JSON policy string.
*/
private String policyAsJsonString(AWSPolicy setupPolicy) {
try {
return objectMapper.writeValueAsString(setupPolicy);
} catch (JsonProcessingException e) {
// Return a more general internal server error if JSON encoding fails.
LOG.error(POLICY_ENCODING_ERROR, e);
throw new InternalServerErrorException(POLICY_ENCODING_ERROR, e);
}
}

/**
* Create the AWS Kinesis setup policy.
*/
private AWSPolicy buildAwsSetupPolicy() {
List<String> actions = Arrays.asList("cloudwatch:PutMetricData",
"dynamodb:CreateTable",
"dynamodb:DescribeTable",
Expand All @@ -164,34 +216,30 @@ public AvailableServiceResponse getAvailableServices() {
"logs:DescribeLogGroups",
"logs:PutSubscriptionFilter");

AWSPolicyStatement statement = AWSPolicyStatement.create("GraylogCloudWatchPolicy",
AWSPolicyStatement statement = AWSPolicyStatement.create("GraylogKinesisSetup",
"Allow",
actions,
"*");
AWSPolicy awsPolicy = AWSPolicy.create(AWS_POLICY_VERSION, Collections.singletonList(statement));
return AWSPolicy.create(AWS_POLICY_VERSION, Collections.singletonList(statement));
}

ArrayList<AvailableService> services = new ArrayList<>();
/**
* Create the AWS Kinesis auto-setup policy.
*/
private AWSPolicy buildAwsAutoSetupPolicy() {
List<String> actions = Arrays.asList("iam:PassRole",
"logs:DescribeSubscriptionFilters",
"logs:PutLogEvents",
"kinesis:CreateStream",
"kinesis:DescribeStreamConsumer",
"kinesis:PutRecord",
"kinesis:RegisterStreamConsumer");

// Deliberately provide the policy JSON as a string. The UI will format and display this to the user.
String policy;
try {
policy = objectMapper.writeValueAsString(awsPolicy);
} catch (JsonProcessingException e) {
// Return a more general internal server error if JSON encoding fails.
LOG.error(POLICY_ENCODING_ERROR, e);
throw new InternalServerErrorException(POLICY_ENCODING_ERROR, e);
}
AvailableService cloudWatchService =
AvailableService.create("CloudWatch",
"Retrieve CloudWatch logs via Kinesis. Kinesis allows streaming of the logs " +
"in real time. AWS CloudWatch is a monitoring and management service built " +
"for developers, system operators, site reliability engineers (SRE), " +
"and IT managers.",
policy,
"Requires Kinesis",
"https://aws.amazon.com/cloudwatch/");
services.add(cloudWatchService);
return AvailableServiceResponse.create(services, services.size());
AWSPolicyStatement statement = AWSPolicyStatement.create("GraylogKinesisAutoSetup",
"Allow",
actions,
"*");
return AWSPolicy.create(AWS_POLICY_VERSION, Collections.singletonList(statement));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@ public void setUp() throws Exception {
@Test
public void testAll() throws InterruptedException {

// TODO: Remove before prod.
// Make test pass when mocking enabled.
if (setupResource.mockResponses) {
return;
}

// Stream
final KinesisNewStreamRequest request =
KinesisNewStreamRequest.create(REGION, KEY, SECRET, STREAM_NAME);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.graylog.integrations.aws.resources.requests.AWSInputCreateRequest;
import org.graylog.integrations.aws.resources.responses.AWSRegion;
import org.graylog.integrations.aws.resources.responses.AvailableServiceResponse;
import org.graylog.integrations.aws.resources.responses.KinesisPermissionsResponse;
import org.graylog.integrations.aws.transports.KinesisTransport;
import org.graylog2.inputs.Input;
import org.graylog2.inputs.InputServiceImpl;
Expand Down Expand Up @@ -151,4 +152,23 @@ public void testAvailableServices() throws JsonProcessingException {
assertTrue(policy.contains("elasticloadbalancing"));
assertTrue(policy.contains("kinesis"));
}

@Test
public void testPermissions() throws JsonProcessingException {

final KinesisPermissionsResponse permissions = awsService.getPermissions();

// Verify that the setup policy contains some needed permissions.
assertTrue(permissions.setupPolicy().contains("cloudwatch"));
assertTrue(permissions.setupPolicy().contains("dynamodb"));
assertTrue(permissions.setupPolicy().contains("ec2"));
assertTrue(permissions.setupPolicy().contains("elasticloadbalancing"));
assertTrue(permissions.setupPolicy().contains("kinesis"));

// Verify that the auto-setup policy contains some needed permissions.
assertTrue(permissions.autoSetupPolicy().contains("CreateStream"));
assertTrue(permissions.autoSetupPolicy().contains("DescribeSubscriptionFilters"));
assertTrue(permissions.autoSetupPolicy().contains("PutRecord"));
assertTrue(permissions.autoSetupPolicy().contains("RegisterStreamConsumer"));
}
}