Skip to content

Commit

Permalink
Merge pull request #64 from rundeck/rundeck-cli-63
Browse files Browse the repository at this point in the history
Add RD_INSECURE_SSL=true to disable SSL cert/hostname checks
  • Loading branch information
gschueler committed Feb 2, 2017
2 parents a845770 + a5d3553 commit 386960d
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 11 deletions.
31 changes: 22 additions & 9 deletions docs/configuration.md
Expand Up @@ -9,7 +9,7 @@ permalink: /configuration/

Export environment variables in your shell, or in a `~/.rd/rd.conf` file (unix only).

**Connection Info**
## Connection Info

export RD_URL=http://rundeck:4440

Expand All @@ -19,7 +19,7 @@ Define a specific API version to use, by using the complete API base:

All requests will be made using that API version.

**Credentials**
## Credentials

Define access credentials as user/password or Token value:

Expand All @@ -30,7 +30,7 @@ Define access credentials as user/password or Token value:
export RD_USER=username
export RD_PASSWORD=password

**Prompting**
## Prompting

If you do not define the credentials as environment variables,
you will be prompted to enter a username/password or token in
Expand All @@ -41,7 +41,7 @@ You can disable automatic prompting:
export RD_AUTH_PROMPT=false


**ANSI color**
## ANSI color

By default, `rd` will print some output using ANSI escapes for colorized output.

Expand All @@ -55,7 +55,7 @@ You can set the default colors used by info/output/error/warning output:
export RD_COLOR_WARN=orange
export RD_COLOR_ERROR=cyan

**Bypass an external URL**:
## Bypass an external URL

If your Rundeck server has a different *external URL* than the one you are accessing,
you can tell the `rd` tool to treat redirects to that external URL as
Expand All @@ -70,7 +70,7 @@ as `http://internal-rundeck:4440/rundeck/blah`.
Note: if you include the API version in your `RD_URL`, e.g. `http://internal-rundeck:4440/rundeck/api/12` then
the `RD_BYPASS_URL` will be replaced by `http://internal-rundeck:4440/rundeck`.

**HTTP/connect timeout**
## HTTP/connect timeout

Use `RD_HTTP_TIMEOUT` env var:

Expand All @@ -80,7 +80,7 @@ Use `RD_HTTP_TIMEOUT` env var:
Note: if the timeout seems longer than you specify, it is because the "connection retry" is set to true
by default.

**Connection Retry**
## Connection Retry

Retry in case of recoverable connection issue (e.g. failure to connect):

Expand All @@ -89,10 +89,23 @@ Use `RD_CONNECT_RETRY` (default `true`):
# don't retry
export RD_CONNECT_RETRY=false

**Debug HTTP**
## Debug HTTP

Use the `RD_DEBUG` env var to turn on HTTP debugging:

export RD_DEBUG=1 # basic http request debug
export RD_DEBUG=2 # http headers
export RD_DEBUG=3 # http body
export RD_DEBUG=3 # http body

## SSL Configuration

See [SSL Configuration]({{site.url}}{{site.baseurl}}/configuration/ssl/)

## Insecure SSL

To disable *all* SSL certificate checks, and hostname verifications:

export RD_INSECURE_SSL=true

When enabled, a value of `RD_DEBUG=2` will also report SSL certificate
information.
6 changes: 4 additions & 2 deletions docs/ssl.md
Expand Up @@ -5,13 +5,15 @@ title: SSL Configuration
permalink: /configuration/ssl/
---

# Setup SSL

To use a self-signed or custom server certificate for `rd`, you will need to do the following:

1. Import the certificate to a truststore/keystore
2. Set the JVM properties needed to use the truststore

(**Note**: if you want to skip the rigamarole, and simply accept *all*
SSL certificates without verification,
see [Configuration - Insecure SSL](({{site.url}}{{site.baseurl}}/configuration/#insecure-ssl))

## 1. Import the certificate

You can get the server certificate in many ways, (e.g. connect to the server in a
Expand Down
76 changes: 76 additions & 0 deletions src/main/java/org/rundeck/client/Rundeck.java
Expand Up @@ -10,8 +10,13 @@
import retrofit2.converter.jackson.JacksonConverterFactory;
import retrofit2.converter.simplexml.SimpleXmlConverterFactory;

import javax.net.ssl.*;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.security.GeneralSecurityException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand All @@ -24,6 +29,8 @@ public class Rundeck {
public static final int API_VERS = 16;
public static final Pattern API_VERS_PATTERN = Pattern.compile("^(.*)(/api/(\\d+)/?)$");
public static final String ENV_BYPASS_URL = "RD_BYPASS_URL";
public static final String ENV_INSECURE_SSL = "RD_INSECURE_SSL";
public static final int INSECURE_SSL_LOGGING = 2;

/**
* Create a client using the specified, or default version
Expand Down Expand Up @@ -102,6 +109,10 @@ public static Client<RundeckApi> client(
.addInterceptor(new StaticHeaderInterceptor("User-Agent", USER_AGENT));

String bypassUrl = System.getProperty("rundeck.client.bypass.url", System.getenv(ENV_BYPASS_URL));
boolean insecureSsl = Boolean.parseBoolean(System.getProperty(
"rundeck.client.insecure.ssl",
System.getenv(ENV_INSECURE_SSL)
));

if (null != bypassUrl) {
//fix redirects to external Rundeck URL by rewriting as to the baseurl
Expand All @@ -110,6 +121,10 @@ public static Client<RundeckApi> client(
bypassUrl
));
}

if (insecureSsl) {
addInsecureSsl(callFactory, httpLogging);
}
if (httpLogging > 0) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();

Expand Down Expand Up @@ -210,6 +225,10 @@ public static Client<RundeckApi> client(

));
String bypassUrl = System.getProperty("rundeck.client.bypass.url", System.getenv(ENV_BYPASS_URL));
boolean insecureSsl = Boolean.parseBoolean(System.getProperty(
"rundeck.client.insecure.ssl",
System.getenv(ENV_INSECURE_SSL)
));

if (null != bypassUrl) {
//fix redirects to external Rundeck URL by rewriting as to the baseurl
Expand All @@ -218,6 +237,9 @@ public static Client<RundeckApi> client(
normalizeUrlPath(bypassUrl)
));
}
if (insecureSsl) {
addInsecureSsl(callFactory, httpLogging);
}
if (httpLogging > 0) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();

Expand Down Expand Up @@ -251,6 +273,60 @@ public static Client<RundeckApi> client(
return new Client<>(build.create(RundeckApi.class), build, usedApiVers);
}

private static void addInsecureSsl(final OkHttpClient.Builder callFactory, int logging) {

X509TrustManager trustManager;
SSLSocketFactory sslSocketFactory;
try {
trustManager = createInsecureSslTrustManager(logging);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{trustManager}, null);
sslSocketFactory = sslContext.getSocketFactory();
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
}
callFactory.sslSocketFactory(sslSocketFactory, trustManager);
callFactory.hostnameVerifier((hostname, session) -> {
if (logging >= INSECURE_SSL_LOGGING) {
System.err.println("INSECURE_SSL:hostnameVerifier: trust host: " + hostname);
}
return true;
});
}

private static X509TrustManager createInsecureSslTrustManager(int logging)
throws GeneralSecurityException
{
return new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] cArrr = new X509Certificate[0];
return cArrr;
}

@Override
public void checkServerTrusted(
final X509Certificate[] chain,
final String authType
) throws CertificateException
{
if (logging >= INSECURE_SSL_LOGGING) {
System.err.printf("INSECURE_SSL:TrustManager:checkServerTrusted: %s: chain: %s%n", authType,
Arrays.toString(chain)
);
}
}

@Override
public void checkClientTrusted(
final X509Certificate[] chain,
final String authType
) throws CertificateException
{
}
};
}

/**
* @param baseUrl input url
* @param apiVers api VERSION to append if /api/VERS is not present
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/org/rundeck/client/tool/Main.java
Expand Up @@ -25,6 +25,8 @@
import java.util.Random;
import java.util.function.Function;

import static org.rundeck.client.Rundeck.ENV_INSECURE_SSL;


/**
* Entrypoint for commandline
Expand Down Expand Up @@ -61,9 +63,13 @@ private static void setupFormat(final ToolBelt belt, AppConfig config) {
representer.addClassTag(Execution.class, Tag.MAP);
belt.formatter(new YamlFormatter(representer, dumperOptions));
belt.channels().infoEnabled(false);
belt.channels().warningEnabled(false);
belt.channels().errorEnabled(false);
} else if ("json".equalsIgnoreCase(config.get("RD_FORMAT"))) {
belt.formatter(new JsonFormatter());
belt.channels().infoEnabled(false);
belt.channels().warningEnabled(false);
belt.channels().errorEnabled(false);
} else {
NiceFormatter formatter = new NiceFormatter(null);
formatter.setCollectionIndicator("");
Expand Down Expand Up @@ -96,6 +102,15 @@ public static Tool tool(final String name, final Rd rd) {
.commandInput(new JewelInput());
setupColor(belt, rd);
setupFormat(belt, rd);

boolean insecureSsl = Boolean.parseBoolean(System.getProperty(
"rundeck.client.insecure.ssl",
System.getenv(ENV_INSECURE_SSL)
));
if (insecureSsl) {
belt.finalOutput().warning(
"# WARNING: RD_INSECURE_SSL=true, no hostname or certificate trust verification will be performed");
}
return belt.buckle();
}

Expand Down

0 comments on commit 386960d

Please sign in to comment.