Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files
AMBARI-24918 - Infra Manager: ssl support (#17)
  • Loading branch information
kasakrisz authored and oleewere committed Nov 21, 2018
1 parent c818680 commit c4c350c98edbb0c830153eb7fe43e944e6dc0c23
Showing 18 changed files with 290 additions and 102 deletions.
@@ -86,7 +86,7 @@ public void add(SolrInputDocument solrInputDocument) {

public void createSolrCollection(String collectionName) {
logger.info("Creating collection");
runCommand(new String[]{"docker", "exec", "docker_solr_1", "solr", "create_collection", "-force", "-c", collectionName, "-d", Paths.get(configSetPath, "configsets", collectionName, "conf").toString(), "-n", collectionName + "_conf"});
runCommand(new String[]{"docker", "exec", "solr", "solr", "create_collection", "-force", "-c", collectionName, "-d", Paths.get(configSetPath, "configsets", collectionName, "conf").toString(), "-n", collectionName + "_conf"});
}

public QueryResponse query(SolrQuery query) {
@@ -52,7 +52,7 @@ public static void setupMetricsServer() throws Exception {
logger.info("Creating new docker containers for testing Ambari Infra Solr Metrics plugin ...");
runCommand(new String[]{shellScriptLocation, "start"});

Solr solr = new Solr("/usr/lib/ambari-infra-solr/server/solr");
Solr solr = new Solr();
solr.waitUntilSolrIsUp();
solr.createSolrCollection(HADOOP_LOGS_COLLECTION);

@@ -15,6 +15,7 @@
version: '3.3'
services:
zookeeper:
container_name: zookeeper
image: zookeeper:${ZOOKEEPER_VERSION:-3.4.10}
restart: always
hostname: zookeeper
@@ -27,6 +28,7 @@ services:
ZOO_SERVERS: server.1=zookeeper:2888:3888
solr:
# TODO: use infra-solr
container_name: solr
image: solr:${SOLR_VERSION:-7.5.0}
restart: always
hostname: solr
@@ -47,6 +49,7 @@ services:
volumes:
- $AMBARI_INFRA_LOCATION/ambari-infra-manager/docker/configsets:/opt/solr/configsets
fakes3:
container_name: fakes3
image: localstack/localstack
hostname: fakes3
ports:
@@ -61,6 +64,7 @@ services:
env_file:
- Profile
namenode:
container_name: hdfs_namenode
image: flokkr/hadoop-hdfs-namenode:${HADOOP_VERSION:-3.0.0}
hostname: namenode
ports:
@@ -73,6 +77,7 @@ services:
networks:
- infra-network
datanode:
container_name: hdfs_datanode
image: flokkr/hadoop-hdfs-datanode:${HADOOP_VERSION:-3.0.0}
links:
- namenode
@@ -81,6 +86,7 @@ services:
networks:
- infra-network
inframanager:
container_name: inframanager
image: ambari-infra-manager:v1.0
restart: always
hostname: infra-manager.apache.org
@@ -18,13 +18,17 @@
*/
package org.apache.ambari.infra.conf;

import static org.apache.commons.lang3.StringUtils.isNotBlank;

import java.time.Duration;

import javax.inject.Inject;

import org.apache.ambari.infra.conf.security.SslSecrets;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.server.Ssl;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;

@@ -34,18 +38,47 @@ public class InfraManagerWebServerCustomizer implements WebServerFactoryCustomiz
@Value("${infra-manager.server.port:61890}")
private int port;

@Value("${infra-manager.server.ssl.enabled:false}")
private boolean sslEnabled;

@Inject
private ServerProperties serverProperties;

@Inject
private SslSecrets sslSecrets;

private static final Integer SESSION_TIMEOUT = 60 * 30;
private static final String INFRA_MANAGER_SESSIONID = "INFRAMANAGER_SESSIONID";
private static final String INFRA_MANAGER_SESSION_ID = "INFRAMANAGER_SESSIONID";
private static final String INFRA_MANAGER_APPLICATION_NAME = "infra-manager";

@Override
public void customize(JettyServletWebServerFactory factory) {
factory.setPort(port);
factory.setDisplayName(INFRA_MANAGER_APPLICATION_NAME);
factory.getSession().getCookie().setName(INFRA_MANAGER_SESSIONID);
factory.getSession().getCookie().setName(INFRA_MANAGER_SESSION_ID);
factory.getSession().setTimeout(Duration.ofSeconds(SESSION_TIMEOUT));

Ssl ssl = new Ssl();
String keyStore = System.getProperty("javax.net.ssl.keyStore");
if (isNotBlank(keyStore)) {
ssl.setKeyStore(keyStore);
ssl.setKeyStoreType(System.getProperty("javax.net.ssl.keyStoreType"));
String keyStorePassword = sslSecrets.getKeyStorePassword().get().orElseThrow(() -> new IllegalStateException("Password for keystore is not set!"));
ssl.setKeyStorePassword(keyStorePassword);
System.setProperty("javax.net.ssl.keyStorePassword", keyStorePassword);
}

String trustStore = System.getProperty("javax.net.ssl.trustStore");
if (isNotBlank(trustStore)) {
ssl.setTrustStore(trustStore);
ssl.setTrustStoreType(System.getProperty("javax.net.ssl.trustStoreType"));
String trustStorePassword = sslSecrets.getTrustStorePassword().get().orElseThrow(() -> new IllegalStateException("Password for truststore is not set!"));
ssl.setKeyStorePassword(trustStorePassword);
System.setProperty("javax.net.ssl.trustStorePassword", trustStorePassword);
}

ssl.setEnabled(sslEnabled);

factory.setSsl(ssl);
}
}
@@ -20,17 +20,17 @@

import java.util.Optional;

public class CompositePasswordStore implements PasswordStore {
private PasswordStore[] passwordStores;
public class CompositeSecret implements Secret {
private Secret[] secrets;

public CompositePasswordStore(PasswordStore... passwordStores) {
this.passwordStores = passwordStores;
public CompositeSecret(Secret... secrets) {
this.secrets = secrets;
}

@Override
public Optional<String> getPassword(String propertyName) {
for (PasswordStore passwordStore : passwordStores) {
Optional<String> optionalPassword = passwordStore.getPassword(propertyName);
public Optional<String> get() {
for (Secret secret : secrets) {
Optional<String> optionalPassword = secret.get();
if (optionalPassword.isPresent())
return optionalPassword;
}
@@ -20,9 +20,16 @@

import java.util.Optional;

public class SecurityEnvironment implements PasswordStore {
public class EnvironmentalSecret implements Secret {

private final String environmentalVariableName;

public EnvironmentalSecret(String environmentalVariableName) {
this.environmentalVariableName = environmentalVariableName;
}

@Override
public Optional<String> getPassword(String propertyName) {
return Optional.ofNullable(System.getenv(propertyName));
public Optional<String> get() {
return Optional.ofNullable(System.getenv(environmentalVariableName));
}
}
@@ -0,0 +1,41 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.ambari.infra.conf.security;

import java.util.Optional;

public class HadoopCredential implements Secret {

private final HadoopCredentialStore hadoopCredentialStore;
private final String propertyName;

public HadoopCredential(HadoopCredentialStore hadoopCredentialStore, String propertyName) {
this.propertyName = propertyName;
this.hadoopCredentialStore = hadoopCredentialStore;
}

@Override
public Optional<String> get() {
if (hadoopCredentialStore == null) {
return Optional.empty();
}

return hadoopCredentialStore.get(propertyName).map(String::new);
}
}
@@ -21,13 +21,11 @@
import static org.apache.commons.lang.StringUtils.isBlank;
import static org.apache.commons.lang3.ArrayUtils.isNotEmpty;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Optional;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class HadoopCredentialStore implements PasswordStore {
private static final Logger logger = LogManager.getLogger(InfraManagerSecurityConfig.class);
public class HadoopCredentialStore {
public static final String CREDENTIAL_STORE_PROVIDER_PATH_PROPERTY = "hadoop.security.credential.provider.path";

private final String credentialStoreProviderPath;
@@ -36,20 +34,22 @@ public HadoopCredentialStore(String credentialStoreProviderPath) {
this.credentialStoreProviderPath = credentialStoreProviderPath;
}

@Override
public Optional<String> getPassword(String propertyName) {
public Optional<char[]> get(String key) {
try {
if (isBlank(credentialStoreProviderPath)) {
return Optional.empty();
}

org.apache.hadoop.conf.Configuration config = new org.apache.hadoop.conf.Configuration();
config.set(CREDENTIAL_STORE_PROVIDER_PATH_PROPERTY, credentialStoreProviderPath);
char[] passwordChars = config.getPassword(propertyName);
return (isNotEmpty(passwordChars)) ? Optional.of(new String(passwordChars)) : Optional.empty();
} catch (Exception e) {
logger.warn("Could not load password {} from credential store.", propertyName);
return Optional.empty();
char[] passwordChars = config.getPassword(key);
return (isNotEmpty(passwordChars)) ? Optional.of(passwordChars) : Optional.empty();
} catch (IOException e) {
throw new UncheckedIOException(String.format("Could not load password %s from credential store.", key), e);
}
}

public Secret getSecret(String key) {
return new HadoopCredential(this, key);
}
}
@@ -18,21 +18,44 @@
*/
package org.apache.ambari.infra.conf.security;

import static org.apache.ambari.infra.conf.security.HadoopCredentialStore.CREDENTIAL_STORE_PROVIDER_PATH_PROPERTY;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import static org.apache.ambari.infra.conf.security.HadoopCredentialStore.CREDENTIAL_STORE_PROVIDER_PATH_PROPERTY;

@Configuration
public class InfraManagerSecurityConfig {

@Value("${"+ CREDENTIAL_STORE_PROVIDER_PATH_PROPERTY + ":}")
private String credentialStoreProviderPath;

@Bean
public HadoopCredentialStore hadoopCredentialStore() {
return new HadoopCredentialStore(credentialStoreProviderPath);
}

@Bean
public S3Secrets s3SecretStore(HadoopCredentialStore hadoopCredentialStore) {
return new S3Secrets(s3AccessKeyId(hadoopCredentialStore), s3SecretKeyId(hadoopCredentialStore));
}

private Secret s3AccessKeyId(HadoopCredentialStore hadoopCredentialStore) {
return new CompositeSecret(
hadoopCredentialStore.getSecret( "AWS_ACCESS_KEY_ID"),
new EnvironmentalSecret("AWS_ACCESS_KEY_ID"));
}

private Secret s3SecretKeyId(HadoopCredentialStore hadoopCredentialStore) {
return new CompositeSecret(
hadoopCredentialStore.getSecret( "AWS_SECRET_ACCESS_KEY"),
new EnvironmentalSecret("AWS_SECRET_ACCESS_KEY"));
}

@Bean
public PasswordStore passwords() {
return new CompositePasswordStore(new HadoopCredentialStore(credentialStoreProviderPath), new SecurityEnvironment());
public SslSecrets sslSecrets(HadoopCredentialStore hadoopCredentialStore) {
return new SslSecrets(
hadoopCredentialStore.getSecret("infra_manager_keystore_password"),
hadoopCredentialStore.getSecret("infra_manager_truststore_password"));
}
}
@@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.ambari.infra.conf.security;

public class S3Secrets {
private final Secret s3AccessKeyId;
private final Secret s3SecretAccessKey;

public S3Secrets(Secret s3AccessKeyId, Secret s3SecretAccessKey) {
this.s3AccessKeyId = s3AccessKeyId;
this.s3SecretAccessKey = s3SecretAccessKey;
}


public Secret getS3AccessKeyId() {
return s3AccessKeyId;
}

public Secret getS3SecretAccessKey() {
return s3SecretAccessKey;
}
}
@@ -20,6 +20,6 @@

import java.util.Optional;

public interface PasswordStore {
Optional<String> getPassword(String propertyName);
public interface Secret {
Optional<String> get();
}

0 comments on commit c4c350c

Please sign in to comment.