Skip to content

Commit

Permalink
Merge pull request #25 from 3KeyCompany/release/1.2.0
Browse files Browse the repository at this point in the history
Release/1.2.0
  • Loading branch information
3keyroman authored Sep 14, 2022
2 parents f5da4ef + 3319eee commit 8612822
Show file tree
Hide file tree
Showing 9 changed files with 335 additions and 5 deletions.
11 changes: 8 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,15 @@ COPY settings.xml /root/.m2/settings.xml
ARG SERVER_USERNAME
ARG SERVER_PASSWORD
RUN mvn -f /home/app/pom.xml clean package
COPY docker /home/app/docker

# Package stage
#FROM openjdk:11-jdk-slim
FROM adoptopenjdk/openjdk11:alpine-jre
#ARG JAR_FILE=target/*.jar
COPY --from=build /home/app/target/*.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

COPY --from=build /home/app/docker /
COPY --from=build /home/app/target/*.jar /opt/czertainly/app.jar

WORKDIR /opt/czertainly

ENTRYPOINT ["/opt/czertainly/entry.sh"]
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,25 @@ EJBCA NG `Connector` is provided as a Docker container. Use the `docker pull har
| `JDBC_PASSWORD` | Password to access the database | Yes | N/A |
| `DB_SCHEMA` | Database schema to use | No | ejbca |
| `PORT` | Port where the service is exposed | No | 8082 |

### Proxy settings

You may need to configure proxy to allow communication with external systems.
To enable proxy, use the following environment variables:

| Variable | Description | Required | Default value |
|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------------|
| `HTTP_PROXY` | The proxy URL to use for http connections. Format: `<protocol>://<proxy_host>:<proxy_port>` or `<protocol>://<user>:<password>@<proxy_host>:<proxy_port>` | No | N/A |
| `HTTPS_PROXY` | The proxy URL to use for https connections. Format: `<protocol>://<proxy_host>:<proxy_port>` or `<protocol>://<user>:<password>@<proxy_host>:<proxy_port>` | No | N/A |
| `NO_PROXY` | A comma-separated list of host names that shouldn't go through any proxy | No | N/A |

Example values:
- `HTTP_PROXY=http://user:password@proxy.example.com:3128`
- `HTTPS_PROXY=http://user:password@proxy.example.com:3128`
- `NO_PROXY=localhost,127.0.0.1,0.0.0.0,10.0.0.0/8,cattle-system.svc,.svc,.cluster.local,my-domain.local`

### Additional trusted certificates

You can inject additional trusted certificates into the container, for example, when your EJBCA is using your internally trusted certificates. To trust additional certificates, you need to map a single file with PEM certificates that should be trusted into `/opt/czertainly/trusted-certificates.pem`.

No worries, you can always change the list of trusted certificates in the future.
17 changes: 17 additions & 0 deletions docker/opt/czertainly/entry.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/sh

czertainlyHome="/opt/czertainly"
source ${czertainlyHome}/static-functions

if [ -f ${czertainlyHome}/trusted-certificates.pem ]
then
log "INFO" "Adding additional trusted certificates to cacerts"
./update-cacerts.sh /opt/czertainly/trusted-certificates.pem
else
log "INFO" "No trusted certificates were provided, continue!"
fi

log "INFO" "Launching the Core"
java -jar ./app.jar

#exec "$@"
17 changes: 17 additions & 0 deletions docker/opt/czertainly/static-functions
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash

log() {
# 2022-02-08 15:49:15
dateString="$(date +%F' '%T)"
logLevel=$(printf '%-5s' "${1:-INFO}")
className="$0"
processId="$$"
#threadId="$(ps H -o 'tid' $processId | tail -n 1| tr -d ' ')"
if [ -z "$2" ] ; then
while read line ; do
echo "[$dateString] $logLevel [$className] (process:$processId) ${line}"
done
else
echo "[$dateString] $logLevel [$className] (process:$processId) ${2}"
fi
}
15 changes: 15 additions & 0 deletions docker/opt/czertainly/update-cacerts.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/sh

PEM_FILE=$1
PASSWORD=changeit
CERTS=$(grep 'END CERTIFICATE' $PEM_FILE| wc -l)

# For every cert in the PEM file, extract it and import into the JKS keystore
# awk command: step 1, if line is in the desired cert, print the line
# step 2, increment counter when last line of cert is found
for N in $(seq 0 $(($CERTS - 1))); do
ALIAS="czertainly-trusted-$N"
cat $PEM_FILE |
awk "n==$N { print }; /END CERTIFICATE/ { n++ }" |
keytool -noprompt -import -trustcacerts -cacerts -alias $ALIAS -storepass $PASSWORD
done
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

<groupId>com.czertainly</groupId>
<artifactId>ejbca-ng-connector</artifactId>
<version>1.1.0</version>
<version>1.2.0</version>
<name>CZERTAINLY-EJBCA-NG-Connector</name>

<properties>
Expand All @@ -36,7 +36,7 @@
<dependency>
<groupId>com.czertainly</groupId>
<artifactId>interfaces</artifactId>
<version>1.3.0</version>
<version>1.4.0</version>
</dependency>

<!-- <dependency>-->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.czertainly.ca.connector.ejbca.config.proxy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.util.HashMap;
import java.util.Map;

/**
* This is an {@link Authenticator} implementation able to manage several servers
* Inspired by <a href="https://github.com/Orange-OpenSource/spring-boot-autoconfigure-proxy">spring-boot-autoconfigure-proxy</a>
*/
public class MultiServerAuthenticator extends Authenticator {
private static final Logger logger = LoggerFactory.getLogger(MultiServerAuthenticator.class);

private final Map<String, PasswordAuthentication> host2Authent = new HashMap<>();

public void add(String host, String user, String password) {
host2Authent.put(host, new PasswordAuthentication(user, password.toCharArray()));
}

@Override
protected PasswordAuthentication getPasswordAuthentication() {
String host = "" + getRequestingHost() + ":" + getRequestingPort();
PasswordAuthentication passwordAuthentication = host2Authent.get(host);
logger.trace("using proxy authentication for <{}>: {}", host, passwordAuthentication == null ? "none" : passwordAuthentication.getUserName() + "/***");
return passwordAuthentication;
}

public int size() {
return host2Authent.size();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.czertainly.ca.connector.ejbca.config.proxy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;

import javax.annotation.PostConstruct;
import java.net.Authenticator;

/**
* Inspired by <a href="https://github.com/Orange-OpenSource/spring-boot-autoconfigure-proxy">spring-boot-autoconfigure-proxy</a>
*/
@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
public class ProxyConfiguration {
private static final Logger logger = LoggerFactory.getLogger(ProxyConfiguration.class);

private static final String[] PROTOCOLS = {"http", "https", "ftp"};

@PostConstruct
public void setupProxyConfiguration() {
MultiServerAuthenticator msa = new MultiServerAuthenticator();

for (String protocol : PROTOCOLS) {
ProxySettings proxySettings = ProxySettings.read(protocol);
if (proxySettings != null) {
// CASE 2: auto-conf from ENV
logger.info("Configuring proxy for {} from env '{}': {}", protocol, proxySettings.getEnvName(), proxySettings);

// set password authentication if specified
if (proxySettings.getUsername() != null && proxySettings.getPassword() != null) {
msa.add(proxySettings.getHost() + ":" + proxySettings.getPort(), proxySettings.getUsername(), proxySettings.getPassword());
}

// set proxy properties
System.setProperty(protocol + ".proxyHost", proxySettings.getHost());
System.setProperty(protocol + ".proxyPort", String.valueOf(proxySettings.getPort()));
if (proxySettings.getNoProxyHosts() != null && proxySettings.getNoProxyHosts().length > 0) {
System.setProperty(protocol + ".nonProxyHosts", String.join("|", proxySettings.getNoProxyHosts()));
}
}
}

// install default authenticator (if not empty)
if (msa.size() > 0) {
// see: https://www.oracle.com/technetwork/java/javase/8u111-relnotes-3124969.html
System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");
Authenticator.setDefault(msa);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package com.czertainly.ca.connector.ejbca.config.proxy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;

/**
* Inspired by <a href="https://github.com/Orange-OpenSource/spring-boot-autoconfigure-proxy">spring-boot-autoconfigure-proxy</a>
*/
public class ProxySettings {

private static final Logger logger = LoggerFactory.getLogger(ProxySettings.class);

private final String forProtocol;
private final String protocol;
private final String host;
private final int port;
private final String[] noProxyHosts;
private final String username;
private final String password;

public ProxySettings(String forProtocol, String protocol, String host, int port, String[] noProxyHosts, String username, String password) {
this.forProtocol = forProtocol;
this.protocol = protocol;
this.username = username;
this.password = password;
this.host = host;
this.noProxyHosts = noProxyHosts;
this.port = port;
}

/**
* Returns the proxy protocol (one of {@code http}, {@code socks} or {@code socks5})
*/
public String getProtocol() {
return protocol;
}

/**
* Returns the protocol (scheme) this proxy setting applies to
*/
public String getForProtocol() {
return forProtocol;
}

/**
* Returns the proxy server host
*/
public String getHost() {
return host;
}

/**
* Returns the proxy server port
*/
public int getPort() {
return port;
}

/**
* Returns the list of no-proxy server hosts (matchers)
*/
public String[] getNoProxyHosts() {
return noProxyHosts;
}

/**
* Returns the proxy username (if requires authentication)
*/
public String getUsername() {
return username;
}

/**
* Returns the proxy password (if requires authentication)
*/
public String getPassword() {
return password;
}

/**
* Returns the proxy setting environment variable name
*/
public String getEnvName() {
return forProtocol + "_proxy";
}

/**
* Returns the proxy setting environment variable value (hides the password)
*/
public String getEnvVal() {
return protocol + "://" + (username == null ? "" : username + ":***@") + host + ":" + port;
}

@Override
public String toString() {
return "ProxySettingsFromEnv{" +
"protocol='" + protocol + '\'' +
", host='" + host + '\'' +
", port=" + port +
", forProtocol=" + forProtocol +
", noProxyHosts=" + Arrays.toString(noProxyHosts) +
", username='" + (username == null ? "(none)" : username) + '\'' +
", password='" + (password == null ? "(none)" : "***") + '\'' +
'}';
}

/**
* Reads and parses the proxy settings from system environment
*
* @param protocol determines for which forProtocol the proxy settings shall be read
* @return parsed setting, or {@code null} if not set
*/
public static ProxySettings read(String protocol) {
return parse(protocol, getEnvIgnoreCase(protocol + "_proxy"), getEnvIgnoreCase("no_proxy"));
}

static ProxySettings parse(String protocol, String proxyUrl, String noProxy) {
if (proxyUrl == null) {
return null;
}
try {
URI url = new URI(proxyUrl);
if (url.getHost() == null) {
logger.error("Invalid proxy configuration URL for {}: {} - host not specified", protocol, proxyUrl);
return null;
}
if (url.getPort() == -1) {
logger.error("Invalid proxy configuration URL for {}: {} - port not specified", protocol, proxyUrl);
return null;
}
// scheme is optional (defaults to http)
String scheme = url.getScheme() == null ? "http" : url.getScheme();

// read login/password
String username = null;
String password = null;
String userInfo = url.getUserInfo();
if (userInfo != null) {
int idx = userInfo.indexOf(':');
username = userInfo.substring(0, idx);
password = userInfo.substring(idx + 1);
}
// add no proxy hosts
String[] noProxyHosts = null;
if (noProxy != null) {
noProxyHosts = noProxy.split("\\s*,\\s*");
}
return new ProxySettings(protocol, scheme, url.getHost(), url.getPort(), noProxyHosts, username, password);
} catch (URISyntaxException e) {
logger.error("Could not decode proxy configuration for {}: {}", protocol, proxyUrl, e);
return null;
}
}


static String getEnvIgnoreCase(String name) {
String val = System.getenv(name.toLowerCase());
return val != null ? val : System.getenv(name.toUpperCase());
}

}

0 comments on commit 8612822

Please sign in to comment.