Skip to content

Commit

Permalink
Add ability to send hostname for TLS SNI extension
Browse files Browse the repository at this point in the history
  • Loading branch information
foxefj-cyber committed Dec 22, 2021
1 parent 7313d48 commit 824b73f
Show file tree
Hide file tree
Showing 16 changed files with 869 additions and 108 deletions.
62 changes: 62 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,68 @@ Rake tasks are easy to run from within the `conjur` server container:
The next available error number is 63 ( CONJ00063E )
```

### Kubernetes specific Cucumber tests

Several cucumber tests are written to verify conjur works properly when
authenticating to Kubernetes. These tests have hooks to run against both
Openshift and Google GKE.

The cucumber tests are located under `cucumber/kubernetes/features` and can be
run by going into the `ci/authn-k8s` directory and running:

```shell
$ summon -f [secrets.ocp.yml|secrets.yml] ./init_k8s.sh [openshift|gke]
$ summon -f [secrets.ocp.yml|secrets.yml] ./test.sh [openshift|gke]
```

* `init_k8s.sh` - executes a simple login to Openshift or GKE to verify
credentials as well as logging into the Docker Registry defined
* `test.sh` - executes the tests against the defined platform

#### Secrets file

The secrets file used for summons needs to contain the following environment
variables

* openshift
* `OPENSHIFT_USERNAME` - username of an account that can create namespaces,
adjust cluster properties, etc
* `OPENSHIFT_PASSWORD` - password of the account
* `OPENSHIFT_URL` - the URL of the RedHat CRC cluster
* If running this locally - use `https://host.docker.internal:6443` so
the docker container can talk to the CRC containers
* `OPENSHIFT_TOKEN` - the login token of the above username/password
* only needed for local execution because the docker container executing
the commands can't redirect for login
* obtained by running the following command locally after login -
`oc whoami -t`
* gke
* `GCLOUD_CLUSTER_NAME` - cluster name of the GKE environment in the cloud
* `GCLOUD_ZONE` - zone of the GKE environment in the cloud
* `GCLOUD_PROJECT_NAME` - project name of the GKE environment
* `GCLOUD_SERVICE_KEY` - service key of the GKE environment

#### Local Execution Prerequisites

To execute the tests locally, a few things will have to be done:

* Openshift
* Download and install the RedHat Code Ready Container
* This contains all the necessary pieces to have a local version of
Openshift
* After install, copy down the kubeadmin username/password and update the
secrets.ocp.yml file with the password
* Execute `oc whoami -t` and update the token property
* GKE
* Work with infrastructure to obtain a GKE environment

If the local revision of your files don't have a docker image built yet - build
the docker images using the following command:

```shell
$ ./build_locally.sh <sni cert file>
```

## Pull Request Workflow

1. [Fork the project](https://help.github.com/en/github/getting-started-with-github/fork-a-repo)
Expand Down
19 changes: 19 additions & 0 deletions app/domain/authentication/authn_k8s/k8s_object_lookup.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ def initialize(webservice = nil)
@cert_store = OpenSSL::X509::Store.new
@cert_store.set_default_paths
::Conjur::CertUtils.add_chained_cert(@cert_store, ca_cert)

return unless ENV.key?('SSL_CERT_DIRECTORY')

load_additional_certs(
ssl_cert_directory: ENV['SSL_CERT_DIRECTORY'],
cert_store: @cert_store,
cert_utils: ::Conjur::CertUtils
)
end

def bearer_token
Expand Down Expand Up @@ -183,6 +191,7 @@ def k8s_clients
KubeClientFactory.client(
api: 'apis/apps.openshift.io', version: 'v1', host_url: api_url,
options: options

)
]
end
Expand All @@ -196,6 +205,16 @@ def handle_object_not_found &block
raise unless $!.error_code == 404
end
end

def load_additional_certs(ssl_cert_directory:, cert_store:, cert_utils:)
# allows us to add additional CA certs for things like SNI certs
if Dir.exist?("#{ssl_cert_directory}/ca")
Dir["#{ssl_cert_directory}/ca/*"].each do |file_name|
cert_utils.add_chained_cert(cert_store, File.read(file_name)) if
File.exist?(file_name)
end
end
end
end
end
end
8 changes: 7 additions & 1 deletion app/domain/authentication/authn_k8s/web_socket_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,22 @@ def connect(url, options = {})
uri.port || (uri.scheme == 'wss' ? 443 : 80))
if %w[https wss].include?(uri.scheme)
ctx = OpenSSL::SSL::SSLContext.new
ctx.ssl_version = options[:ssl_version] || 'SSLv23'
ssl_version = options[:ssl_version] || 'SSLv23'
ctx.ssl_version = ssl_version
ctx.verify_mode = options[:verify_mode] || OpenSSL::SSL::VERIFY_NONE # use VERIFY_PEER for verification
cert_store = options[:cert_store]
unless cert_store
cert_store = OpenSSL::X509::Store.new
cert_store.set_default_paths
end
ctx.cert_store = cert_store

@socket = ::OpenSSL::SSL::SSLSocket.new(@socket, ctx)
if ssl_version != 'SSLv23'
@socket.hostname = options[:hostname] || uri.host
end
@socket.connect
@socket.post_connection_check(@socket.hostname) if @socket.hostname
end
@handshake = ::WebSocket::Handshake::Client.new(url: url, headers: options[:headers])
@handshaked = false
Expand Down
4 changes: 3 additions & 1 deletion ci/authn-k8s/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
dev/interventions/*.gke.yml
dev/tls/nginx.*
dev/tls/*.key
dev/tls/*.crt
nginx.crt
/output/
dev/**/*.openshift.yml
30 changes: 30 additions & 0 deletions ci/authn-k8s/build_locally.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/bash

sni_cert=$1

if [[ ! -z "$sni_cert" ]]; then
sni_cert="$(realpath $1)"
fi

function copy_cert() {
image=$1
sni_cert=$2

if [[ ! -z $sni_cert ]]; then
docker rm temp_container || true
docker create --name temp_container "$image"
docker cp "$sni_cert" "temp_container:/opt/conjur/etc/ssl/ca/${sni_cert##*/}"
docker commit temp_container "$image"
docker rm temp_container
fi
}

cd "$(git rev-parse --show-toplevel)" || exit

TAG="$(git rev-parse --short=8 HEAD)"
export TAG="$TAG"
docker build --no-cache -t "conjur:$TAG" .
copy_cert "conjur:$TAG" "$sni_cert"
docker build --no-cache -t "registry.tld/conjur:$TAG" .
copy_cert "registry.tld/conjur:$TAG" "$sni_cert"
docker build --no-cache --build-arg "VERSION=$TAG" -t "registry.tld/conjur-test:$TAG" -f Dockerfile.test .
58 changes: 58 additions & 0 deletions ci/authn-k8s/dev/dev_conjur_sni.template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: conjur-authn-k8s
labels:
app: conjur-authn-k8s
spec:
replicas: 1
selector:
matchLabels:
app: conjur-authn-k8s
template:
metadata:
labels:
app: conjur-authn-k8s
spec:
hostAliases:
- ip: {{ KUBERNETES_SERVICE_HOST }}
hostnames:
- "{{ KUBERNETES_API_FQDN }}"
containers:
- image: {{ CONJUR_AUTHN_K8S_TAG }}
imagePullPolicy: Always
name: conjur
command: ["conjurctl", "server"]
env:
- name: DATABASE_URL
value: postgres://postgres@postgres:5432/postgres
- name: CONJUR_ADMIN_PASSWORD
value: admin
- name: CONJUR_ACCOUNT
value: cucumber
- name: CONJUR_DATA_KEY
value: "{{ DATA_KEY }}"
- name: RAILS_ENV
value: test
# Enable coverage tracking.
- name: REQUIRE_SIMPLECOV
value: "true"
# Sleep after generating the coverage report to keep the pod alive
# so the report can be retrieved.
- name: SIMPLECOV_SLEEP
value: "true"
- name: WEB_CONCURRENCY
value: "0"
- name: RAILS_MAX_THREADS
value: "10"
- name: CONJUR_AUTHENTICATORS
value: authn-k8s/minikube
- name: KUBERNETES_SERVICE_HOST
value: {{ KUBERNETES_API_FQDN }}
volumeMounts:
- mountPath: /run/authn-local
name: authn-local
volumes:
- name: authn-local
emptyDir:
medium: Memory
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ metadata:
name: inventory-deployment-cfg
spec:
replicas: 1
selector:
matchLabels:
app: inventory-deployment-cfg
selector:
app: inventory-deployment-cfg
template:
metadata:
labels:
Expand Down
39 changes: 39 additions & 0 deletions ci/authn-k8s/dev/tls/api-test-com.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
[req]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn
x509_extensions = v3_ca # The extentions to add to the self signed cert
req_extensions = v3_req
x509_extensions = usr_cert

[ dn ]
C = US
ST = Wisconsin
L = Madison
O = CyberArk
OU = Onyx
CN = api.test.com

[ usr_cert ]
basicConstraints = CA:FALSE
nsCertType = client, server, email
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth, clientAuth, codeSigning, emailProtection
nsComment = "OpenSSL Generated Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer

[ v3_req ]
extendedKeyUsage = serverAuth, clientAuth, codeSigning, emailProtection
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment

[ v3_ca ]
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = localhost
DNS.2 = api.test.com
IP.1 = 127.0.0.1
11 changes: 9 additions & 2 deletions ci/authn-k8s/dev/utils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ function initialize_gke() {

function initialize_oc() {
# setup kubectl, oc and docker
oc login $OPENSHIFT_URL --username=$OPENSHIFT_USERNAME --password=$OPENSHIFT_PASSWORD --insecure-skip-tls-verify=true
docker login -u _ -p $(oc whoami -t) $OPENSHIFT_REGISTRY_URL
url=$OPENSHIFT_URL

if [ -z "$OPENSHIFT_TOKEN" ]; then
oc login $url --username="$OPENSHIFT_USERNAME" --password="$OPENSHIFT_PASSWORD" --insecure-skip-tls-verify=true
else
oc login $url --token="$OPENSHIFT_TOKEN" --insecure-skip-tls-verify=true
fi

docker login -u _ -p "$(oc whoami -t)" "$OPENSHIFT_REGISTRY_URL"
}
12 changes: 12 additions & 0 deletions ci/authn-k8s/secrets.ocp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#OPENSHIFT_URL: !var dev/openshift/current/api-url
#OPENSHIFT_USERNAME: !var dev/openshift/current/username
#OPENSHIFT_PASSWORD: !var dev/openshift/current/password
#OPENSHIFT_REGISTRY_URL: !var dev/openshift/current/registry-url

OPENSHIFT_USERNAME: kubeadmin
OPENSHIFT_PASSWORD: A753x-ziqxZ-VFjmX-GxrAy
OPENSHIFT_REGISTRY_URL: default-route-openshift-image-registry.apps-crc.testing
OPENSHIFT_URL: https://host.docker.internal:6443
OPENSHIFT_TOKEN: sha256~u6bQl0-d3RoMGKMun_Kcm5GRygMHq4a7Qqvelmr29Mg

OPENSHIFT_CLI_URL: https://github.com/openshift/origin/releases/download/v3.11.0/openshift-origin-client-tools-v3.11.0-0cbc58b-linux-64bit.tar.gz
27 changes: 16 additions & 11 deletions ci/authn-k8s/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function main() {
setupTestEnvironment $PLATFORM

createNginxCert

buildDockerImages

case "$PLATFORM" in
Expand Down Expand Up @@ -77,25 +77,29 @@ function buildDockerImages() {
conjur_version=$(echo "$(git rev-parse --short=8 HEAD)")
DOCKER_REGISTRY_PATH="registry.tld"

docker pull $DOCKER_REGISTRY_PATH/conjur:$conjur_version
docker pull $DOCKER_REGISTRY_PATH/conjur-test:$conjur_version
if ! docker image inspect "$DOCKER_REGISTRY_PATH/conjur:$conjur_version" > /dev/null 2>&1; then
docker pull "$DOCKER_REGISTRY_PATH/conjur:$conjur_version"
fi
if ! docker image inspect "$DOCKER_REGISTRY_PATH/conjur-test:$conjur_version" > /dev/null 2>&1; then
docker pull "$DOCKER_REGISTRY_PATH/conjur-test:$conjur_version"
fi

docker tag $DOCKER_REGISTRY_PATH/conjur:$conjur_version $CONJUR_AUTHN_K8S_TAG
docker tag "$DOCKER_REGISTRY_PATH/conjur:$conjur_version" "$CONJUR_AUTHN_K8S_TAG"

# cukes will be run from this image
docker tag $DOCKER_REGISTRY_PATH/conjur-test:$conjur_version $CONJUR_TEST_AUTHN_K8S_TAG
docker tag "$DOCKER_REGISTRY_PATH/conjur-test:$conjur_version" "$CONJUR_TEST_AUTHN_K8S_TAG"

docker build -t $INVENTORY_BASE_TAG -f dev/Dockerfile.inventory_base dev
docker build -t "$INVENTORY_BASE_TAG" -f dev/Dockerfile.inventory_base dev
docker build \
--build-arg INVENTORY_BASE_TAG=$INVENTORY_BASE_TAG \
-t $INVENTORY_TAG \
--build-arg INVENTORY_BASE_TAG="$INVENTORY_BASE_TAG" \
-t "$INVENTORY_TAG" \
-f dev/Dockerfile.inventory \
dev

docker build -t $NGINX_TAG -f dev/Dockerfile.nginx dev
docker build -t "$NGINX_TAG" -f dev/Dockerfile.nginx dev

docker build --build-arg OPENSHIFT_CLI_URL=$OPENSHIFT_CLI_URL \
-t $CONJUR_AUTHN_K8S_TESTER_TAG -f dev/Dockerfile.test dev
docker build --build-arg OPENSHIFT_CLI_URL="$OPENSHIFT_CLI_URL" \
-t "$CONJUR_AUTHN_K8S_TESTER_TAG" -f dev/Dockerfile.test dev
}

function test_gke() {
Expand Down Expand Up @@ -130,6 +134,7 @@ function test_openshift() {
-e OPENSHIFT_REGISTRY_URL \
-e OPENSHIFT_USERNAME \
-e OPENSHIFT_PASSWORD \
-e OPENSHIFT_TOKEN \
-v /var/run/docker.sock:/var/run/docker.sock \
-v "$PWD":/src \
$CONJUR_AUTHN_K8S_TESTER_TAG bash -c "./test_oc_entrypoint.sh"
Expand Down
Loading

0 comments on commit 824b73f

Please sign in to comment.