diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index 82a033c..aedf62e --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ /node_modules +/output +/custom_tls_cert_gen/output yarn.lock \ No newline at end of file diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/build_manager.sh b/build_manager.sh index ac70b26..0c0feb5 100755 --- a/build_manager.sh +++ b/build_manager.sh @@ -210,6 +210,36 @@ function generate_portainer_jwt() { curl -d ${payload} -H 'Content-Type: application/json' "http://${address}:9000/api/auth" } +function get_portainer_ce_api_reference() { + printf "${HIGHLIGHT_COLOR}Get the reference of Portainer CE API${NO_COLOR}\n" + + cd ${WORKDIR}/portainer + + if ! check_branch; then + exit; + fi + + read -p "Commit(HEAD):" commit + if [ -z "$commit" ]; then + commit=$(git rev-parse HEAD) + fi + printf "${HIGHLIGHT_COLOR}Installing github.com/portainer/portainer/api@${commit}${NO_COLOR}\n" + + output=$(go install github.com/portainer/portainer/api@${commit}) | while IFS= read -r line; do + echo "$line" + done + + # result=" + # go: downloading github.com/portainer/portainer/api v0.0.0-20220622202437-f0ca3e63db9d + # go: downloading github.com/portainer/portainer v0.6.1-0.20220622202437-f0ca3e63db9d + # package github.com/portainer/portainer/api is not a main package + # " + + # while IFS= read -r line; do + # echo "$line" + # done <<< $(echo ${result}) +} + function menu() { PS3='Please select the option: ' OPTIONS=( @@ -218,6 +248,7 @@ function menu() { 'Build Portainer EE/CE Backend' 'Generate Portainer EE/CE JWT' 'Run Before Commit [Portainer EE/CE]' + 'Get Portainer CE API Reference' 'Run Before Commit [k8s]' 'Build Portainer Agent' 'Cleanup Temporary Volume' @@ -242,6 +273,9 @@ function menu() { 'Run Before Commit [Portainer EE/CE]') run_before_commit ;; + 'Get Portainer CE API Reference') + get_portainer_ce_api_reference + ;; 'Run Before Commit [k8s]') run_before_commit_k8s ;; diff --git a/custom_tls_cert_gen/generate-custom-tls.sh b/custom_tls_cert_gen/generate-custom-tls.sh new file mode 100755 index 0000000..c6a6aa0 --- /dev/null +++ b/custom_tls_cert_gen/generate-custom-tls.sh @@ -0,0 +1,94 @@ +#!/bin/bash + +set -eu + +source ../utils/common.sh + +input "Specify the output path:" OUTPUT_PATH + +if [ -z "$OUTPUT_PATH" ]; then + OUTPUT_PATH="$(pwd)/output" + + if [[ ! -e "$OUTPUT_PATH" ]]; then + mkdir "$OUTPUT_PATH" + fi +fi + +if [[ ! -e "$OUTPUT_PATH" ]]; then + print_error "${OUTPUT_PATH} doesn't exist." + exit; +fi + +rm -rvf "$OUTPUT_PATH/*" + +input "Do you have cfssl installed?(y/n): " is_cfssl_installed + +CFSSLEXE=${OUTPUT_PATH}/cfssl +CFSSLJSONEXE=${OUTPUT_PATH}/cfssljson + +if [[ "${is_cfssl_installed}" == "y" || "${is_cfssl_installed}" == "Y" ]]; then + input "Specify the path where the cfssl and cfssljson are placed: " TOOL_PATH + + CFSSLEXE=${TOOL_PATH}/cfssl + CFSSLJSONEXE=${TOOL_PATH}/cfssljson + + print_highlight "Your cfssl binary path is ${CFSSLEXE}" + + if [ ! -e "$CFSSLEXE" ]; then + print_error "no cfssl found." + exit; + fi + + if [ ! -e "$CFSSLJSONEXE" ]; then + print_error "no cfssljson found." + exit; + fi + +else + # Download the cfssl for users + input "Specify your platform(darwin/linux/windows): " PLATFORM + + if [ -z "$PLATFORM" ]; then + print_error "Platform must be provided." + exit; + fi + + print_highlight "Only amd64 is supported" + + wget "https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssl_1.6.1_${PLATFORM}_amd64" -O "${OUTPUT_PATH}/cfssl" + chmod +x "${OUTPUT_PATH}/cfssl" + wget "https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssljson_1.6.1_${PLATFORM}_amd64" -O "${OUTPUT_PATH}/cfssljson" + chmod +x "${OUTPUT_PATH}/cfssljson" + + print_highlight "Download the cfssl bundle successfully." +fi + +cd $OUTPUT_PATH + +input "Give a name to the CA certificate: " CA_CERT_NAME + +CA_CERT_NAME=${CA_CERT_NAME}-ca + +${CFSSLEXE} print-defaults csr | ${CFSSLEXE} gencert -initca - | ${CFSSLJSONEXE} -bare ${CA_CERT_NAME} + +CONFIG_CFSSL_JSON=${OUTPUT_PATH}/cfssl.json + +cat <> ${CONFIG_CFSSL_JSON} +{ + "signing": { + "default": { + "expiry": "87600h", + "usages": ["signing", "key encipherment", "server auth"] + } + } +} +EOF + +input "Give a name to the certificate: " CERT_NAME + +input "Input the hostname(example.org,127.0.0.1): " CERT_HOSTNAME + +echo '{}' | ${CFSSLEXE} gencert -ca=${CA_CERT_NAME}.pem -ca-key=${CA_CERT_NAME}-key.pem -config=${CONFIG_CFSSL_JSON} \ + -hostname="${CERT_HOSTNAME}" - | ${CFSSLJSONEXE} -bare ${CERT_NAME} + +print_highlight "The custom TLS certificates are successfully generated in the path ${OUTPUT_PATH}." diff --git a/images/setup-openldap.gif b/images/setup-openldap.gif new file mode 100644 index 0000000..311f06c Binary files /dev/null and b/images/setup-openldap.gif differ diff --git a/ldap_service/README.md b/ldap_service/README.md new file mode 100644 index 0000000..9749b32 --- /dev/null +++ b/ldap_service/README.md @@ -0,0 +1,32 @@ +# LDAP + + +This will setup portainer with testing image and openldap service with bootstrap data + StartTLS/TLS enabled + +## 1. How to start? + +``` +git clone https://github.com/oscarzhou/portainer-openldap-quick-setup.git && cd portainer-openldap-quick-setup +chmod +x ldap-run.sh +./ldap-run.sh +``` + +![setup-openldap](/images/setup-openldap.gif) + +After the output `Portainer run up successfully` shows up, it may take a while for portainer to finish initialization. You can refresh the web page every 5 seconds. + + +## 2. How to test? + +| Key | Value | +|---|---| +| Admin Login DN | cn=admin,dc=example,dc=org | +| Admin Password | admin_pass | +| Server IP | 172.31.0.10 | +| Port over TLS (STARTTLS) | 389 | +| Port over SSL | 636 | +| CA Certificate | ./data/certs/ldap-ca.pem | +| username1 | developer | +| password1 | developer_pass | +| username2 | maintainer | +| password2 | maintainer_pass | diff --git a/ldap_service/data/bootstrap.ldif b/ldap_service/data/bootstrap.ldif new file mode 100644 index 0000000..696246f --- /dev/null +++ b/ldap_service/data/bootstrap.ldif @@ -0,0 +1,54 @@ +dn: cn=developer,dc=example,dc=org +changetype: add +objectclass: inetOrgPerson +cn: developer +givenname: developer +sn: Developer +displayname: Developer User +mail: developer@gmail.com +uid: developer +userpassword: developer_pass + +dn: cn=maintainer,dc=example,dc=org +changetype: add +objectclass: inetOrgPerson +cn: maintainer +givenname: maintainer +sn: Maintainer +displayname: Maintainer User +mail: maintainer@gmail.com +uid: maintainer +userpassword: maintainer_pass + +dn: cn=admin_gh,dc=example,dc=org +changetype: add +objectclass: inetOrgPerson +cn: admin_gh +givenname: admin_gh +sn: AdminGithub +displayname: Admin Github User +mail: admin_gh@gmail.com +userpassword: admin_gh_pass + +dn: ou=Groups,dc=example,dc=org +changetype: add +objectclass: organizationalUnit +ou: Groups + +dn: ou=Users,dc=example,dc=org +changetype: add +objectclass: organizationalUnit +ou: Users + +dn: cn=Admins,ou=Groups,dc=example,dc=org +changetype: add +cn: Admins +objectclass: groupOfUniqueNames +uniqueMember: cn=admin_gh,dc=example,dc=org + +dn: cn=Maintainers,ou=Groups,dc=example,dc=org +changetype: add +cn: Maintainers +objectclass: groupOfUniqueNames +uniqueMember: cn=maintainer,dc=example,dc=org +uniqueMember: cn=developer,dc=example,dc=org \ No newline at end of file diff --git a/ldap_service/data/certs/cfssl.json b/ldap_service/data/certs/cfssl.json new file mode 100644 index 0000000..87639fd --- /dev/null +++ b/ldap_service/data/certs/cfssl.json @@ -0,0 +1,8 @@ +{ + "signing": { + "default": { + "expiry": "87600h", + "usages": ["signing", "key encipherment", "server auth"] + } + } +} diff --git a/ldap_service/data/certs/ldap-ca-key.pem b/ldap_service/data/certs/ldap-ca-key.pem new file mode 100644 index 0000000..894e8b6 --- /dev/null +++ b/ldap_service/data/certs/ldap-ca-key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIOnBF74dtgfFSwUZlY3WPHjLyedZ3YI5H5jrEu33FeX0oAoGCCqGSM49 +AwEHoUQDQgAEc7tkckI5XrRSf+QeUhk4xnSJdabwgpPVY9vg+DdpFocK7i99ubI+ +p5rBX9xrKGKlcEmM/Yufh32b1drdHmQFaQ== +-----END EC PRIVATE KEY----- diff --git a/ldap_service/data/certs/ldap-ca.csr b/ldap_service/data/certs/ldap-ca.csr new file mode 100644 index 0000000..5308a97 --- /dev/null +++ b/ldap_service/data/certs/ldap-ca.csr @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIBPTCB5AIBADBIMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcT +DVNhbiBGcmFuY2lzY28xFDASBgNVBAMTC2V4YW1wbGUubmV0MFkwEwYHKoZIzj0C +AQYIKoZIzj0DAQcDQgAEc7tkckI5XrRSf+QeUhk4xnSJdabwgpPVY9vg+DdpFocK +7i99ubI+p5rBX9xrKGKlcEmM/Yufh32b1drdHmQFaaA6MDgGCSqGSIb3DQEJDjEr +MCkwJwYDVR0RBCAwHoILZXhhbXBsZS5uZXSCD3d3dy5leGFtcGxlLm5ldDAKBggq +hkjOPQQDAgNIADBFAiEA8F+6ILOqzCzCuPB+sgUALDeud27CEu9nIM16cG710ioC +IBPdKdWivdCVG+YO/+mYb/g3Hbk5vByB9xj1bVQtt7KE +-----END CERTIFICATE REQUEST----- diff --git a/ldap_service/data/certs/ldap-ca.pem b/ldap_service/data/certs/ldap-ca.pem new file mode 100644 index 0000000..99b0a7b --- /dev/null +++ b/ldap_service/data/certs/ldap-ca.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIB0zCCAXqgAwIBAgIUGzxUvE3E82RNYhT+eG2Hscq7ma4wCgYIKoZIzj0EAwIw +SDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNp +c2NvMRQwEgYDVQQDEwtleGFtcGxlLm5ldDAeFw0yMjA4MTEyMjM4MDBaFw0yNzA4 +MTAyMjM4MDBaMEgxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMN +U2FuIEZyYW5jaXNjbzEUMBIGA1UEAxMLZXhhbXBsZS5uZXQwWTATBgcqhkjOPQIB +BggqhkjOPQMBBwNCAARzu2RyQjletFJ/5B5SGTjGdIl1pvCCk9Vj2+D4N2kWhwru +L325sj6nmsFf3GsoYqVwSYz9i5+HfZvV2t0eZAVpo0IwQDAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOBglz2vX3F2/QSfPb8CE6WgX +xowwCgYIKoZIzj0EAwIDRwAwRAIgTPJwMJ/C1AWyduH1VHateYtwSsSiG4CFof/m +e7Te0SACIDo8NbjqCxX5q7xNREx/KrWAGblLlk00Ywsqc+qZejC0 +-----END CERTIFICATE----- diff --git a/ldap_service/data/certs/server-key.pem b/ldap_service/data/certs/server-key.pem new file mode 100644 index 0000000..102e256 --- /dev/null +++ b/ldap_service/data/certs/server-key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIIxGYodBnPD2v4PlKVfTZYkPl2kf9ckdT63NRVI8pJt8oAoGCCqGSM49 +AwEHoUQDQgAEj0t/ND963wlU/FFeiwI7cSBqkOX4puNwOz/npMwVwYLuVOrY/L+s +hjPrZ32WW3lAu3NKsG7bkbDzzw76ppbY1w== +-----END EC PRIVATE KEY----- diff --git a/ldap_service/data/certs/server.csr b/ldap_service/data/certs/server.csr new file mode 100644 index 0000000..9e909e9 --- /dev/null +++ b/ldap_service/data/certs/server.csr @@ -0,0 +1,8 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIBADCBpwIBADAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEj0t/ND963wlU +/FFeiwI7cSBqkOX4puNwOz/npMwVwYLuVOrY/L+shjPrZ32WW3lAu3NKsG7bkbDz +zw76ppbY16BFMEMGCSqGSIb3DQEJDjE2MDQwMgYDVR0RBCswKYIQbGRhcC5leGFt +cGxlLm9yZ4IJbG9jYWxob3N0hwSsHwAKhwR/AAABMAoGCCqGSM49BAMCA0gAMEUC +IQCMPYIchbVmp1bmvT77sucgUf4fe7CGSdOVWkL3rxkTjAIgIhHivuP62hOyG43O +xWi/83L01C7MiOOsQMu6x3NEYQI= +-----END CERTIFICATE REQUEST----- diff --git a/ldap_service/data/certs/server.pem b/ldap_service/data/certs/server.pem new file mode 100644 index 0000000..3b5ae74 --- /dev/null +++ b/ldap_service/data/certs/server.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB+DCCAZ6gAwIBAgIUTj+0B76Ev+XH/iW7lPdo28KM884wCgYIKoZIzj0EAwIw +SDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNp +c2NvMRQwEgYDVQQDEwtleGFtcGxlLm5ldDAeFw0yMjA4MTEyMjM4MDBaFw0zMjA4 +MDgyMjM4MDBaMAAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASPS380P3rfCVT8 +UV6LAjtxIGqQ5fim43A7P+ekzBXBgu5U6tj8v6yGM+tnfZZbeUC7c0qwbtuRsPPP +DvqmltjXo4GtMIGqMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcD +ATAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSefdqGwGdpVarg54WkJioV315BOzAf +BgNVHSMEGDAWgBQ4GCXPa9fcXb9BJ89vwITpaBfGjDA1BgNVHREBAf8EKzApghBs +ZGFwLmV4YW1wbGUub3Jngglsb2NhbGhvc3SHBKwfAAqHBH8AAAEwCgYIKoZIzj0E +AwIDSAAwRQIgIyv9Rifo3PThZm43YJ2nEIeOVANoUHaS1eD34YfLO64CIQDOvpMk +WtM/tAn7ufxdRcN51ev6maK6yQMiu4Hj6Fk4gg== +-----END CERTIFICATE----- diff --git a/ldap_service/docker-compose.yml b/ldap_service/docker-compose.yml new file mode 100644 index 0000000..a19a680 --- /dev/null +++ b/ldap_service/docker-compose.yml @@ -0,0 +1,47 @@ +version: '3.7' + +services: + ldap_server: + image: osixia/openldap:1.5.0 + container_name: ldap_server + environment: + LDAP_ADMIN_PASSWORD: admin_pass + LDAP_BASE_DN: dc=example,dc=org + LDAP_DOMAIN: example.org + LDAP_ORGANISATION: "Example Inc." + LDAP_TLS_CRT_FILENAME: server.pem + LDAP_TLS_KEY_FILENAME: server-key.pem + LDAP_TLS_CA_CRT_FILENAME: ldap-ca.pem + LDAP_TLS_VERIFY_CLIENT: try + hostname: ldap.example.org + command: --copy-service + networks: + default: + ipv4_address: 172.31.0.10 + ports: + - 389:389 + - 636:636 + volumes: + - ./data/bootstrap.ldif:/container/service/slapd/assets/config/bootstrap/ldif/50-bootstrap.ldif + - ./data/certs:/container/service/slapd/assets/certs + + ldap_server_admin: + image: osixia/phpldapadmin:0.7.2 + container_name: ldap_server_admin + ports: + - 8090:80 + networks: + default: + ipv4_address: 172.31.0.2 + environment: + PHPLDAPADMIN_LDAP_HOSTS: ldap_server + PHPLDAPADMIN_HTTPS: 'false' + +networks: + default: + external: false + name: openldap-network + ipam: + driver: default + config: + - subnet: "172.31.0.1/16" diff --git a/ldap_service/ldap-run.sh b/ldap_service/ldap-run.sh new file mode 100755 index 0000000..5fddf18 --- /dev/null +++ b/ldap_service/ldap-run.sh @@ -0,0 +1,117 @@ +#!/bin/bash + +set -eu + +source ../utils/common.sh + +DOCKER_COMPOSE_FILE=./docker-compose.yml +BOOTSTRAP_FILE=./data/bootstrap.ldif +CA_CERT_FILE=./data/certs/ldap-ca.pem +CERT_FILE=./data/certs/server.pem +KEY_FILE=./data/certs/server-key.pem + +print_highlight "Start setup ldap service..." + +docker-compose -v | grep 'docker-compose version' &> /dev/null +if [ $? != 0 ]; then + print_error "docker-compose not detected" + exit; +fi + +print_highlight "docker-compose detected" &> /dev/null + +set +e +docker container ls -a | grep 'portainer_ldap' &> /dev/null +if [ $? == 0 ]; then + docker stop portainer_ldap + docker rm portainer_ldap + print_highlight "removing existing container portainer_ldap" +fi + +docker volume ls | grep 'portainer_ldap_data' +if [ $? == 0 ]; then + docker volume rm portainer_ldap_data + print_highlight "removing existing volume portainer_ldap_data" +fi + +docker container ls -a | grep 'ldap_server' &> /dev/null +if [ $? == 0 ]; then + docker stop ldap_server + docker rm ldap_server + print_highlight "removing existing container ldap_server" +fi + +docker container ls -a | grep 'ldap_server_admin' &> /dev/null +if [ $? == 0 ]; then + docker stop ldap_server_admin + docker rm ldap_server_admin + print_highlight "removing existing container ldap_server_admin" +fi + +docker network ls | grep 'openldap-network' &> /dev/null +if [ $? == 0 ]; then + docker network rm openldap-network + print_highlight "removing existing container openldap-network" +fi +set -e + +if [[ ! -e "${DOCKER_COMPOSE_FILE}" ]]; then + print_error "${DOCKER_COMPOSE_FILE} not found" + exit; +fi + +if [[ ! -e "${BOOTSTRAP_FILE}" ]]; then + print_error "${BOOTSTRAP_FILE} not found" + exit; +fi + +if [[ ! -e "${CA_CERT_FILE}" ]]; then + print_error "${CA_CERT_FILE } not found" + exit; +fi + +if [[ ! -e "${CERT_FILE}" ]]; then + print_error "${CERT_FILE} not found" + exit; +fi + +if [[ ! -e "${KEY_FILE}" ]]; then + print_error "${KEY_FILE } not found" + exit; +fi + + +docker-compose up -d + +print_highlight "Open LDAP service run up successfully." + +print_highlight "Login DN(username): cn=admin,dc=example,dc=org" +print_highlight "Password: admin_pass" + +sleep 5 + +xdg-open http://localhost:8090 + +sleep 5 + +input "Input your testing docker image(portainerci/portainer-ee:prxxx): " TEST_IMAGE + +docker volume create portainer_ldap_data + +docker run -d \ +-p 8000:8000 \ +-p 9000:9000 \ +-p 9443:9443 \ +--network openldap-network \ +--name portainer_ldap \ +--restart=always \ +-v /var/run/docker.sock:/var/run/docker.sock \ +-v /portainer_ldap_data:/data \ +${TEST_IMAGE} + +print_highlight "Portainer run up successfully." + +sleep 10 + +xdg-open http://localhost:9000 + diff --git a/utils/common.sh b/utils/common.sh new file mode 100644 index 0000000..b736d58 --- /dev/null +++ b/utils/common.sh @@ -0,0 +1,20 @@ +#!/bin/bash + + +ERROR_COLOR='\033[0;31m'; +HIGHLIGHT_COLOR='\033[0;32m'; +INPUT_COLOR='\033[0;33m'; +NO_COLOR='\033[0m'; + + +function print_highlight() { + printf "${HIGHLIGHT_COLOR}$1${NO_COLOR}\n" +} + +function print_error() { + printf "${ERROR_COLOR}$1${NO_COLOR}\n" +} + +function input() { + read -p "$(echo -e ${INPUT_COLOR}$1 ${NO_COLOR})" $2 +} \ No newline at end of file