Skip to content
This repository has been archived by the owner on Jan 12, 2024. It is now read-only.

Commit

Permalink
Add restore complete command
Browse files Browse the repository at this point in the history
  • Loading branch information
fieldju committed Feb 27, 2017
1 parent c2cf5b6 commit 57b0069
Show file tree
Hide file tree
Showing 11 changed files with 578 additions and 30 deletions.
2 changes: 1 addition & 1 deletion debug.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ cd "$(dirname "$0")"
./gradlew clean sJ

# Run
java -Xdebug -Xrunjdwp:transport=dt_socket,address=5005,server=y,suspend=y -jar ./build/libs/cerberus.jar "$@"
java -Xdebug -Xrunjdwp:transport=dt_socket,address=5006,server=y,suspend=y -jar ./build/libs/cerberus.jar "$@"
2 changes: 1 addition & 1 deletion gradle/dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ allprojects {
compile group: 'com.amazonaws', name: 'aws-java-sdk-sns', version: awsSDKVersion
compile group: 'com.amazonaws', name: 'aws-java-sdk-lambda', version: awsSDKVersion

compile 'com.nike:vault-client:1.0.0'
compile 'com.nike:vault-client:1.1.1'
compile 'com.squareup.okhttp3:okhttp:3.3.1'
compile 'com.beust:jcommander:1.55'
compile 'com.fasterxml.jackson.core:jackson-core:2.7.+'
Expand Down
30 changes: 15 additions & 15 deletions gradle/integration.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,23 @@
* limitations under the License.
*/

subprojects {
sourceSets {
integration {
java.srcDir file('src/integration/java')
resources.srcDir file('src/integration/resources')
sourceSets {
integrationTest {
java {
compileClasspath += main.output + test.output
runtimeClasspath += main.output + test.output
srcDir file('src/integration-test/java')
}
resources.srcDir file('src/integration-test/resources')
}
}

task integration(type: Test, description: 'Runs integration tests') {
testClassesDir = sourceSets.integration.output.classesDir
classpath = sourceSets.integration.runtimeClasspath
}
configurations {
integrationTestCompile.extendsFrom testCompile
integrationTestRuntime.extendsFrom testRuntime
}

dependencies {
integrationCompile sourceSets.main.output
integrationCompile configurations.testCompile
integrationCompile sourceSets.test.output
integrationRuntime configurations.testRuntime
}
task integrationTest(type: Test) {
testClassesDir = sourceSets.integrationTest.output.classesDir
classpath = sourceSets.integrationTest.runtimeClasspath
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright (c) 2017 Nike, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.nike.cerberus.operation;

import com.nike.cerberus.command.core.RestoreCompleteCerberusDataFromS3BackupCommand;
import com.nike.cerberus.module.CerberusModule;
import com.nike.cerberus.operation.core.RestoreCompleteCerberusDataFromS3BackupOperation;
import com.nike.cerberus.util.EnvVarUtils;
import com.nike.cerberus.vault.VaultAdminClientFactory;
import com.nike.vault.client.StaticVaultUrlResolver;
import com.nike.vault.client.VaultAdminClient;
import okhttp3.OkHttpClient;
import org.junit.Before;
import org.junit.Test;

import java.util.Optional;
import java.util.concurrent.TimeUnit;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class RestoreCompleteCerberusDataFromS3BackupOperationIntegrationTest {

private static final int DEFAULT_TIMEOUT = 15;

private static final TimeUnit DEFAULT_TIMEOUT_UNIT = TimeUnit.SECONDS;

private final String apiUrl = EnvVarUtils.getEnvVar("CERBERUS_URL", "Which Cerberus API to use");
private final String token = EnvVarUtils.getEnvVar("TOKEN", "The Token to use for restoring data");
private final String bucket = EnvVarUtils.getEnvVar("S3_BUCKET", "The bucket that contains the backups");
private final String prefix = EnvVarUtils.getEnvVar("S3_PREFIX", "The bucket that contains the backups");
private final String s3Region = EnvVarUtils.getEnvVar("S3_BUCKET_REGION", "The Region that the backup bucket is in");

private RestoreCompleteCerberusDataFromS3BackupOperation operation;

@Before
public void before() {
VaultAdminClientFactory vaultAdminClientFactory = mock(VaultAdminClientFactory.class);
VaultAdminClient adminClient = new VaultAdminClient(
new StaticVaultUrlResolver("http://127.0.0.1:8200"),
new VaultAdminClientFactory.RootCredentialsProvider(token),
new OkHttpClient.Builder()
.connectTimeout(DEFAULT_TIMEOUT, DEFAULT_TIMEOUT_UNIT)
.writeTimeout(DEFAULT_TIMEOUT, DEFAULT_TIMEOUT_UNIT)
.readTimeout(DEFAULT_TIMEOUT, DEFAULT_TIMEOUT_UNIT)
.build());
when(vaultAdminClientFactory.getClientForLeader()).thenReturn(Optional.of(adminClient));

CerberusModule module = new CerberusModule(null, null, null);
operation = new RestoreCompleteCerberusDataFromS3BackupOperation(vaultAdminClientFactory, module.configObjectMapper());
}

@Test
public void test_that_the_restore_complete_operation_can_restore_a_valid_backup_from_s3() {
RestoreCompleteCerberusDataFromS3BackupCommand command = mock(RestoreCompleteCerberusDataFromS3BackupCommand.class);
when(command.getS3Region()).thenReturn(s3Region);
when(command.getS3Bucket()).thenReturn(bucket);
when(command.getS3Prefix()).thenReturn(prefix);
when(command.getCerberusUrl()).thenReturn(apiUrl);

operation.run(command);


}

}
31 changes: 31 additions & 0 deletions src/integration-test/java/com/nike/cerberus/util/EnvVarUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2017 Nike, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.nike.cerberus.util;

public class EnvVarUtils {

private EnvVarUtils() {}

public static String getEnvVar(String key, String message) {
String value = System.getenv(key);
if (value == null || value.equals("")) {
throw new IllegalStateException(String.format("%s is a required environment variable, Message: %s", key, message));
}
return value;
}

}
4 changes: 2 additions & 2 deletions src/main/java/com/nike/cerberus/cli/CerberusRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@

import ch.qos.logback.classic.Level;
import com.beust.jcommander.JCommander;
import com.beust.jcommander.MissingCommandException;
import com.beust.jcommander.ParameterDescription;
import com.beust.jcommander.ParameterException;
import com.beust.jcommander.WrappedParameter;
import com.beust.jcommander.internal.Lists;
import com.github.tomaslanger.chalk.Chalk;
Expand All @@ -39,6 +37,7 @@
import com.nike.cerberus.command.consul.CreateVaultAclCommand;
import com.nike.cerberus.command.core.CreateBaseCommand;
import com.nike.cerberus.command.core.PrintStackInfoCommand;
import com.nike.cerberus.command.core.RestoreCompleteCerberusDataFromS3BackupCommand;
import com.nike.cerberus.command.core.UpdateStackCommand;
import com.nike.cerberus.command.core.UploadCertFilesCommand;
import com.nike.cerberus.command.core.WhitelistCidrForVpcAccessCommand;
Expand Down Expand Up @@ -260,6 +259,7 @@ private void registerAllCommands() {
registerCommand(new CreateCloudFrontLogProcessingLambdaConfigCommand());
registerCommand(new CreateCloudFrontSecurityGroupUpdaterLambdaCommand());
registerCommand(new WhitelistCidrForVpcAccessCommand());
registerCommand(new RestoreCompleteCerberusDataFromS3BackupCommand());
}

/**
Expand Down
89 changes: 89 additions & 0 deletions src/main/java/com/nike/cerberus/client/CerberusAdminClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2017 Nike, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.nike.cerberus.client;

import com.nike.vault.client.UrlResolver;
import com.nike.vault.client.VaultAdminClient;
import com.nike.vault.client.VaultClientException;
import com.nike.vault.client.auth.VaultCredentialsProvider;
import com.nike.vault.client.http.HttpHeader;
import com.nike.vault.client.http.HttpMethod;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

import javax.net.ssl.SSLException;
import java.io.IOException;

/**
*
*/
public class CerberusAdminClient extends VaultAdminClient {

protected OkHttpClient httpClient;
protected VaultCredentialsProvider credentialsProvider;

/**
* Explicit constructor that allows for full control over construction of the Vault client.
*
* @param vaultUrlResolver URL resolver for Vault
* @param credentialsProvider Credential provider for acquiring a token for interacting with Vault
* @param httpClient HTTP client for calling Vault
*/
public CerberusAdminClient(UrlResolver vaultUrlResolver,
VaultCredentialsProvider credentialsProvider,
OkHttpClient httpClient) {

super(vaultUrlResolver, credentialsProvider, httpClient);
this.httpClient = httpClient;
this.credentialsProvider = credentialsProvider;
}

public void restoreMetadata(String jsonPayload) {
HttpUrl url = buildUrl("v1/", "metadata");
Response response = execute(url, HttpMethod.PUT, jsonPayload);
if (! response.isSuccessful()) {
throw new RuntimeException("Failed to restore metadata with cms body: " + response.message());
}
}

protected Response execute(final HttpUrl url, final String method, final String json) {
try {
Request.Builder requestBuilder = new Request.Builder()
.url(url)
.addHeader(HttpHeader.VAULT_TOKEN, credentialsProvider.getCredentials().getToken())
.addHeader(HttpHeader.ACCEPT, DEFAULT_MEDIA_TYPE.toString());

requestBuilder.addHeader(HttpHeader.CONTENT_TYPE, DEFAULT_MEDIA_TYPE.toString())
.method(method, RequestBody.create(DEFAULT_MEDIA_TYPE, json));

return httpClient.newCall(requestBuilder.build()).execute();
} catch (IOException e) {
if (e instanceof SSLException
&& e.getMessage() != null
&& e.getMessage().contains("Unrecognized SSL message, plaintext connection?")) {
// AnyConnect web security proxy can be disabled with:
// `sudo /opt/cisco/anyconnect/bin/acwebsecagent -disablesvc -websecurity`
throw new VaultClientException("I/O error while communicating with vault. Unrecognized SSL message may be due to a web proxy e.g. AnyConnect", e);
} else {
throw new VaultClientException("I/O error while communicating with vault.", e);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright (c) 2017 Nike, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.nike.cerberus.command.core;

import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.nike.cerberus.command.Command;
import com.nike.cerberus.operation.Operation;
import com.nike.cerberus.operation.core.RestoreCompleteCerberusDataFromS3BackupOperation;

import static com.nike.cerberus.command.core.WhitelistCidrForVpcAccessCommand.COMMAND_NAME;

/**
* Command for restoring Safe Deposit Box Metadata and Vault secret data for SDBs from backups that are in S3 from
* the cross region backup lambda.
*/
@Parameters(
commandNames = COMMAND_NAME,
commandDescription = "Allows Cerberus operators to restore a complete backup from S3 that was created using the cross region backup lambda."
)
public class RestoreCompleteCerberusDataFromS3BackupCommand implements Command {

public static final String COMMAND_NAME = "restore-complete";

@Parameter(names = "-s3-region",
description = "The region for the bucket that contains the backups",
required = true
)
private String s3Region;

@Parameter(names = "-s3-bucket",
description = "The bucket that contains the backups",
required = true
)
private String s3Bucket;

@Parameter(names = "-s3-prefix",
description = "the folder that contains the json backup files",
required = true
)
private String s3Prefix;

@Parameter(names = "-url",
description = "The cerberus api, to restore to",
required = true
)
private String cerberusUrl;

public String getS3Region() {
return s3Region;
}

public String getS3Bucket() {
return s3Bucket;
}

public String getS3Prefix() {
return s3Prefix;
}

public String getCerberusUrl() {
return cerberusUrl;
}

@Override
public String getCommandName() {
return COMMAND_NAME;
}

@Override
public Class<? extends Operation<?>> getOperationClass() {
return RestoreCompleteCerberusDataFromS3BackupOperation.class;
}
}
Loading

0 comments on commit 57b0069

Please sign in to comment.