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

feat(secret): decrypt secrets before sending to deck #1379

Merged
merged 4 commits into from
Aug 1, 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
@@ -0,0 +1,32 @@
package com.netflix.spinnaker.halyard.deploy.config.v1.secrets;

import com.netflix.spinnaker.halyard.core.secrets.v1.SecretSessionManager;
import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.Profile;
import com.netflix.spinnaker.kork.secrets.EncryptedSecret;
import java.nio.file.Path;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class BindingsSecretDecrypter {
private SecretSessionManager secretSessionManager;

@Autowired
BindingsSecretDecrypter(SecretSessionManager secretSessionManager) {
this.secretSessionManager = secretSessionManager;
}

public String trackSecretFile(Profile profile, Path outputDir, String value, String fieldName) {
if (!EncryptedSecret.isEncryptedSecret(value)) {
return value;
}
String decryptedFilename = newRandomFileName(fieldName);
profile.getDecryptedFiles().put(decryptedFilename, secretSessionManager.decryptAsBytes(value));
return outputDir.resolve(decryptedFilename).toString();
}

private String newRandomFileName(String fieldName) {
return fieldName + "-" + RandomStringUtils.randomAlphanumeric(5);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ protected ArtifactService getArtifactService() {

@Override
protected Map<String, Object> getBindings(
DeploymentConfiguration deploymentConfiguration, SpinnakerRuntimeSettings endpoints) {
DeploymentConfiguration deploymentConfiguration,
Profile profile,
SpinnakerRuntimeSettings endpoints) {
Map<String, Object> result = new HashMap<>();
result.put("accessKeyId", accessKeyId);
result.put(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ protected String getMinimumSecretDecryptionVersion(String deploymentName) {
* @return true if the target service supports decryption of secrets
*/
protected boolean supportsSecretDecryption(String deploymentName) {
if (getArtifact().equals(SpinnakerArtifact.DECK)) {
return false;
}
String minVersion = getMinimumSecretDecryptionVersion(deploymentName);
if (minVersion == null) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ public abstract class TemplateBackedProfileFactory extends ProfileFactory {
protected abstract String getTemplate();

protected abstract Map<String, Object> getBindings(
DeploymentConfiguration deploymentConfiguration, SpinnakerRuntimeSettings endpoints);
DeploymentConfiguration deploymentConfiguration,
Profile profile,
SpinnakerRuntimeSettings endpoints);

protected List<String> requiredFiles(DeploymentConfiguration deploymentConfiguration) {
return new ArrayList<>();
Expand All @@ -46,7 +48,7 @@ protected void setProfile(
SpinnakerRuntimeSettings endpoints) {
StringResource template = new StringResource(profile.getBaseContents());
profile.setRequiredFiles(requiredFiles(deploymentConfiguration));
Map<String, Object> bindings = getBindings(deploymentConfiguration, endpoints);
Map<String, Object> bindings = getBindings(deploymentConfiguration, profile, endpoints);
profile.setContents(template.setBindings(bindings).toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.netflix.spinnaker.halyard.config.model.v1.node.DeploymentConfiguration;
import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerArtifact;
import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerRuntimeSettings;
import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.Profile;
import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.TemplateBackedProfileFactory;
import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service.ServiceSettings;
import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service.SpinnakerService.Type;
Expand Down Expand Up @@ -51,7 +52,9 @@ public class ConsulClientProfileFactory extends TemplateBackedProfileFactory {

@Override
protected Map<String, Object> getBindings(
DeploymentConfiguration deploymentConfiguration, SpinnakerRuntimeSettings endpoints) {
DeploymentConfiguration deploymentConfiguration,
Profile profile,
SpinnakerRuntimeSettings endpoints) {
Map<String, Object> bindings = new HashMap<>();
ServiceSettings consul = endpoints.getServiceSettings(Type.CONSUL_CLIENT);
bindings.put("scheme", consul.getScheme());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerRuntimeSettings;
import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.Profile;
import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.TemplateBackedProfileFactory;
import com.netflix.spinnaker.kork.secrets.EncryptedSecret;
import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Component;
Expand Down Expand Up @@ -52,10 +53,17 @@ protected void setProfile(

@Override
protected Map<String, Object> getBindings(
DeploymentConfiguration deploymentConfiguration, SpinnakerRuntimeSettings endpoints) {
DeploymentConfiguration deploymentConfiguration,
Profile profile,
SpinnakerRuntimeSettings endpoints) {
Map<String, Object> bindings = new HashMap<>();
ApacheSsl ssl = deploymentConfiguration.getSecurity().getUiSecurity().getSsl();
bindings.put("passphrase", ssl.getSslCertificatePassphrase());
if (EncryptedSecret.isEncryptedSecret(ssl.getSslCertificatePassphrase())
&& !supportsSecretDecryption(deploymentConfiguration.getName())) {
bindings.put("passphrase", secretSessionManager.decrypt(ssl.getSslCertificatePassphrase()));
} else {
bindings.put("passphrase", ssl.getSslCertificatePassphrase());
}
return bindings;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ protected void setProfile(

@Override
protected Map<String, Object> getBindings(
DeploymentConfiguration deploymentConfiguration, SpinnakerRuntimeSettings endpoints) {
DeploymentConfiguration deploymentConfiguration,
Profile profile,
SpinnakerRuntimeSettings endpoints) {
Map<String, Object> bindings = new HashMap<>();
bindings.put("deck-host", endpoints.getServiceSettings(Type.DECK).getHost());
bindings.put("deck-port", endpoints.getServiceSettings(Type.DECK).getPort() + "");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.netflix.spinnaker.halyard.config.model.v1.security.UiSecurity;
import com.netflix.spinnaker.halyard.core.resource.v1.StringResource;
import com.netflix.spinnaker.halyard.core.resource.v1.TemplatedResource;
import com.netflix.spinnaker.halyard.deploy.config.v1.secrets.BindingsSecretDecrypter;
import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerArtifact;
import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerRuntimeSettings;
import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.Profile;
Expand All @@ -30,6 +31,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
Expand All @@ -55,6 +57,8 @@ public class ApacheSpinnakerProfileFactory extends TemplateBackedProfileFactory
" </Directory>",
"</VirtualHost>");

@Autowired BindingsSecretDecrypter bindingsSecretDecrypter;

@Override
protected String getTemplate() {
return SPINNAKER_TEMPLATE;
Expand All @@ -77,13 +81,35 @@ protected void setProfile(

@Override
protected Map<String, Object> getBindings(
DeploymentConfiguration deploymentConfiguration, SpinnakerRuntimeSettings endpoints) {
DeploymentConfiguration deploymentConfiguration,
Profile profile,
SpinnakerRuntimeSettings endpoints) {
TemplatedResource resource = new StringResource(SSL_TEMPLATE);
Map<String, Object> bindings = new HashMap<>();
UiSecurity uiSecurity = deploymentConfiguration.getSecurity().getUiSecurity();
ApacheSsl apacheSsl = uiSecurity.getSsl();
bindings.put("cert-file", apacheSsl.getSslCertificateFile());
bindings.put("key-file", apacheSsl.getSslCertificateKeyFile());
if (supportsSecretDecryption(deploymentConfiguration.getName())) {
bindings.put("cert-file", apacheSsl.getSslCertificateFile());
bindings.put("key-file", apacheSsl.getSslCertificateKeyFile());
} else {
bindings.put(
"cert-file",
bindingsSecretDecrypter.trackSecretFile(
profile,
halconfigDirectoryStructure.getStagingDependenciesPath(
deploymentConfiguration.getName()),
apacheSsl.getSslCertificateFile(),
"sslCertificateFile"));
bindings.put(
"key-file",
bindingsSecretDecrypter.trackSecretFile(
profile,
halconfigDirectoryStructure.getStagingDependenciesPath(
deploymentConfiguration.getName()),
apacheSsl.getSslCertificateKeyFile(),
"sslCertificateKeyFile"));
}

String ssl = resource.setBindings(bindings).toString();
bindings.clear();
bindings.put("ssl", ssl);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.netflix.spinnaker.halyard.config.model.v1.node.DeploymentConfiguration;
import com.netflix.spinnaker.halyard.config.model.v1.security.ApacheSsl;
import com.netflix.spinnaker.halyard.config.services.v1.AccountService;
import com.netflix.spinnaker.halyard.deploy.config.v1.secrets.BindingsSecretDecrypter;
import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerArtifact;
import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerRuntimeSettings;
import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.Profile;
Expand All @@ -33,6 +34,8 @@
public class DeckDockerProfileFactory extends DeckProfileFactory {
@Autowired AccountService accountService;

@Autowired BindingsSecretDecrypter bindingsSecretDecrypter;

@Override
public String commentPrefix() {
return "// ";
Expand All @@ -59,9 +62,30 @@ protected void setProfile(
env.put("DECK_HOST", deckSettings.getHost());
env.put("DECK_PORT", deckSettings.getPort() + "");
env.put("API_HOST", gateSettings.getBaseUrl());
env.put("DECK_CERT", apacheSsl.getSslCertificateFile());
env.put("DECK_KEY", apacheSsl.getSslCertificateKeyFile());
env.put("PASSPHRASE", apacheSsl.getSslCertificatePassphrase());
if (supportsSecretDecryption(deploymentConfiguration.getName())) {
env.put("DECK_CERT", apacheSsl.getSslCertificateFile());
env.put("DECK_KEY", apacheSsl.getSslCertificateKeyFile());
env.put("PASSPHRASE", apacheSsl.getSslCertificatePassphrase());
} else {
env.put(
"DECK_CERT",
bindingsSecretDecrypter.trackSecretFile(
profile,
halconfigDirectoryStructure.getStagingDependenciesPath(
deploymentConfiguration.getName()),
apacheSsl.getSslCertificateFile(),
"sslCertificateFile"));
env.put(
"DECK_KEY",
bindingsSecretDecrypter.trackSecretFile(
profile,
halconfigDirectoryStructure.getStagingDependenciesPath(
deploymentConfiguration.getName()),
apacheSsl.getSslCertificateKeyFile(),
"sslCertificateKeyFile"));
env.put(
"PASSPHRASE", secretSessionManager.decrypt(apacheSsl.getSslCertificatePassphrase()));
}
}

env.put(
Expand Down