Skip to content

Commit

Permalink
Merge pull request #15 from kekru/development
Browse files Browse the repository at this point in the history
Update Nginx, Configure CA expiration and tests for cert generation
  • Loading branch information
kekru authored Oct 10, 2020
2 parents a18ecb5 + 7500210 commit 61dc07c
Show file tree
Hide file tree
Showing 9 changed files with 197 additions and 29 deletions.
17 changes: 9 additions & 8 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
FROM nginx:1.15.12-alpine
# Original Dockerfile: https://github.com/nginxinc/docker-nginx/tree/5488180ebdd45b12b45107694dfa92dc878a2795/stable/alpine
FROM nginx:1.18.0-alpine
LABEL MAINTAINER="Kevin Krummenauer <[email protected]>"
RUN apk add --no-cache openssl

COPY resources /script
COPY resources/create-certs.sh /script/create-certs.sh
COPY resources/nginx-cert.conf /etc/nginx/nginx.conf
COPY resources/entrypoint.sh /docker-entrypoint.d/30_entrypoint.sh

RUN cp /script/nginx-cert.conf /etc/nginx/nginx.conf \
&& chmod +x /script/create-certs.sh /script/entrypoint.sh
RUN chmod +x /script/create-certs.sh /docker-entrypoint.d/30_entrypoint.sh

ENV CREATE_CERTS_WITH_PW="" \
CERTS_DIR=/data/certs \
CERT_HOSTNAME="myserver.example.com"

ENTRYPOINT ["/script/entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]
CERT_HOSTNAME="abc.127.0.0.1.nip.io" \
CERT_EXPIRATION_DAYS="365" \
CA_EXPIRATION_DAYS="900"

HEALTHCHECK --start-period=1s \
--interval=5s \
Expand Down
30 changes: 25 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Create a docker-compose.yml file:
version: "3.4"
services:
remote-api:
image: kekru/docker-remote-api-tls:v0.2.0
image: kekru/docker-remote-api-tls:v0.3.0
ports:
- 2376:443
volumes:
Expand All @@ -47,7 +47,7 @@ Create a docker-compose.yml file, specifying a password and the hostname, on whi
version: "3.4"
services:
remote-api:
image: kekru/docker-remote-api-tls:v0.2.0
image: kekru/docker-remote-api-tls:v0.3.0
ports:
- 2376:443
environment:
Expand All @@ -72,11 +72,15 @@ Certificate passphrase will be read from this docker secret. Absolute path of th

If both passphrase and secret file are set, the secret file takes precedence.

#### `CERT_EXPIRATION`
Certificate expiration in days. If not set, the default value 365 is applied.
#### `CERT_EXPIRATION_DAYS`
Certificate expiration for server and client certs in days. If not set, the default value 365 is applied.

#### `CA_EXPIRATION_DAYS`
Certificate expiration for CA in days. If not set, the default value 900 is applied.

#### `CERT_HOSTNAME`
Domain name of the docker server.
Domain name of the docker server.
If you don't have a DNS name, you can use [nip.io](https://nip.io) to get a name for any IP.

## Setup client

Expand All @@ -95,3 +99,19 @@ docker-compose up -d
# Run ps over remote api (use GitBash when you are on Windows)
./dockerRemote ps
```

## Changelog

#### v0.2.0

First stable release
Thanks [@smiller171](https://github.com/smiller171) for contributing!

#### v0.3.0

+ update nginx version
+ add configuration for cert expiration
+ add configuration to use swarm secret as password for cert generation
+ add automatic tests

Thanks [@benkorichard](https://github.com/benkorichard) for contributing!
6 changes: 1 addition & 5 deletions resources/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
#!/bin/sh

CERT_EXPIRATION_DAYS=${CERT_EXPIRATION:-365}

if [ -n "$CERTS_PASSWORD_FILE" ]; then
echo "Using cert password from $CERTS_PASSWORD_FILE"
CREATE_CERTS_WITH_PW="$(cat $CERTS_PASSWORD_FILE)"
Expand All @@ -11,7 +9,7 @@ if [ -n $CREATE_CERTS_WITH_PW ]; then
if [ -z "$(ls -A $CERTS_DIR)" ]; then

echo "Create CA cert"
/script/create-certs.sh -m ca -pw $CREATE_CERTS_WITH_PW -t $CERTS_DIR -e 900
/script/create-certs.sh -m ca -pw $CREATE_CERTS_WITH_PW -t $CERTS_DIR -e $CA_EXPIRATION_DAYS
echo "Create server cert"
/script/create-certs.sh -m server -h $CERT_HOSTNAME -pw $CREATE_CERTS_WITH_PW -t $CERTS_DIR -e $CERT_EXPIRATION_DAYS
echo "Create client cert"
Expand All @@ -29,5 +27,3 @@ if [ -n $CREATE_CERTS_WITH_PW ]; then
echo "$CERTS_DIR is not empty. Not creating certs."
fi
fi

exec "$@"
2 changes: 0 additions & 2 deletions test/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ services:
- 30129:443
env_file:
- ./target/integr-test/remote-api.env
environment:
- CERT_HOSTNAME=abc.127.0.0.1.nip.io
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,20 @@
import static org.junit.Assert.assertThrows;

import de.kekru.dockerremoteapitls.test.utils.AbstractIntegrationTest;
import de.kekru.dockerremoteapitls.test.utils.CertUtils;
import java.io.File;
import java.time.LocalDate;
import org.junit.BeforeClass;
import org.junit.Test;

public class BasicConnectionTest extends AbstractIntegrationTest {

@BeforeClass
public static void init() {
startRemoteApiContainer("CREATE_CERTS_WITH_PW=supersecret");
startRemoteApiContainer(
"CERT_HOSTNAME=abc.127.0.0.1.nip.io",
"CREATE_CERTS_WITH_PW=supersecret"
);
}

@Test
Expand Down Expand Up @@ -54,4 +60,40 @@ public void failsOnNoTls() {
.hasMessageContaining("error during connect: Get http://abc.127.0.0.1.nip.io:30129/v1.40/containers/json: EOF");
}

@Test
public void caCertHasCorrectDefaultValues() {

CertUtils caCert = new CertUtils(new File(certsDir + "/ca-cert.pem"));

assertThat(caCert.getCert().getSubjectDN().getName())
.isEqualTo("[email protected], CN=example.com, OU=IT, O=ExampleCompany, L=London, ST=London, C=GB");

assertThat(caCert.getExpiresAt())
.isEqualTo(LocalDate.now().plusDays(900));
}

@Test
public void serverCertHasCorrectDefaultValues() {

CertUtils caCert = new CertUtils(new File(certsDir + "/server-cert.pem"));

assertThat(caCert.getCert().getSubjectDN().getName())
.isEqualTo("CN=abc.127.0.0.1.nip.io");

assertThat(caCert.getExpiresAt())
.isEqualTo(LocalDate.now().plusDays(365));
}

@Test
public void clientCertHasCorrectDefaultValues() {

CertUtils caCert = new CertUtils(new File(certsDirClient + "/cert.pem"));

assertThat(caCert.getCert().getSubjectDN().getName())
.isEqualTo("CN=testClient");

assertThat(caCert.getExpiresAt())
.isEqualTo(LocalDate.now().plusDays(365));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package de.kekru.dockerremoteapitls.test;

import static org.assertj.core.api.Assertions.assertThat;

import de.kekru.dockerremoteapitls.test.utils.AbstractIntegrationTest;
import de.kekru.dockerremoteapitls.test.utils.CertUtils;
import java.io.File;
import java.io.IOException;
import java.time.LocalDate;
import org.apache.commons.io.FileUtils;
import org.junit.BeforeClass;
import org.junit.Test;

public class CertGenerationTest extends AbstractIntegrationTest {

@BeforeClass
public static void init() {
startRemoteApiContainer(
"CERT_HOSTNAME=something-else.127.0.0.1.nip.io",
"CREATE_CERTS_WITH_PW=supersecret123",
"CERT_EXPIRATION_DAYS=17",
"CA_EXPIRATION_DAYS=1273"
);
}

@Test
public void caCertHasCorrectDefaultValues() {

CertUtils caCert = new CertUtils(new File(certsDir + "/ca-cert.pem"));

assertThat(caCert.getCert().getSubjectDN().getName())
.isEqualTo("[email protected], CN=example.com, OU=IT, O=ExampleCompany, L=London, ST=London, C=GB");

assertThat(caCert.getExpiresAt())
.isEqualTo(LocalDate.now().plusDays(1273));
}

@Test
public void serverCertHasCorrectDefaultValues() {

CertUtils caCert = new CertUtils(new File(certsDir + "/server-cert.pem"));

assertThat(caCert.getCert().getSubjectDN().getName())
.isEqualTo("CN=something-else.127.0.0.1.nip.io");

assertThat(caCert.getExpiresAt())
.isEqualTo(LocalDate.now().plusDays(17));
}

@Test
public void clientCertHasCorrectDefaultValues() {

CertUtils caCert = new CertUtils(new File(certsDirClient + "/cert.pem"));

assertThat(caCert.getCert().getSubjectDN().getName())
.isEqualTo("CN=testClient");

assertThat(caCert.getExpiresAt())
.isEqualTo(LocalDate.now().plusDays(17));
}

@Test
public void caCertInClientDirIsSameAsInServerDir() throws IOException {

String ca = FileUtils.readFileToString(new File(certsDir + "/ca-cert.pem"), "UTF-8");
String caInClientDir = FileUtils.readFileToString(new File(certsDirClient + "/ca.pem"), "UTF-8");

assertThat(ca).isEqualTo(caInClientDir);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ public class WrongCertTest extends AbstractIntegrationTest {

@BeforeClass
public static void init() {
startRemoteApiContainer("CREATE_CERTS_WITH_PW=supersecret");
startRemoteApiContainer(
"CERT_HOSTNAME=abc.127.0.0.1.nip.io",
"CREATE_CERTS_WITH_PW=supersecret"
);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,14 @@ public class AbstractIntegrationTest {

@ClassRule
public static TemporaryFolder folder = new TemporaryFolder();
protected static ShellExecutor shellExecutor = new ShellExecutor();
protected static File certsDir;
protected static File certsDirClient;
protected static File remoteApiEnvFile;
protected static final ShellExecutor shellExecutor = new ShellExecutor();
protected static final File certsDir = new File("target/integr-test/certs");
protected static final File certsDirClient = new File(certsDir + "/client");
protected static final File remoteApiEnvFile = new File("target/integr-test/remote-api.env");


@BeforeClass
public static void initTests() throws IOException {
remoteApiEnvFile = new File("target/integr-test/remote-api.env");
certsDir = new File("target/integr-test/certs");
certsDirClient = new File(certsDir + "/client");
if (certsDir.exists()) {
FileUtils.cleanDirectory(certsDir);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package de.kekru.dockerremoteapitls.test.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
import javax.security.cert.X509Certificate;

public class CertUtils {

private final X509Certificate cert;

public CertUtils(File file) {
cert = getCert(file);
}

private X509Certificate getCert(File file) {
try (InputStream in = new FileInputStream(file)) {
return X509Certificate.getInstance(in);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

public LocalDate getExpiresAt() {
return toLocalDate(cert.getNotAfter());
}

public LocalDate toLocalDate(Date dateToConvert) {
return dateToConvert.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate();
}

public X509Certificate getCert() {
return cert;
}
}

0 comments on commit 61dc07c

Please sign in to comment.