├── Dockerfile ├── README.md ├── bin ├── entry.sh ├── openvpn-auth.py ├── openvpn-auth.sh └── openvpn-get-client-config.sh └── build.sh /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:jessie 2 | MAINTAINER Alexis Ducastel 3 | 4 | RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \ 5 | easy-rsa \ 6 | dnsutils \ 7 | iptables \ 8 | netmask \ 9 | mawk \ 10 | rsync \ 11 | openssl \ 12 | openvpn \ 13 | python-kerberos \ 14 | python-ldap \ 15 | python-paramiko \ 16 | python-requests \ 17 | wget \ 18 | && apt-get clean 19 | 20 | COPY bin/* /usr/local/bin/ 21 | RUN chmod 744 /usr/local/bin/entry.sh && \ 22 | chown root:root /usr/local/bin/entry.sh && \ 23 | chmod 744 /usr/local/bin/openvpn-* && \ 24 | chown root:root /usr/local/bin/openvpn-* 25 | 26 | CMD ["/usr/local/bin/entry.sh"] 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenVPN for Rancher with modular authentication 2 | 3 | OpenVPN server image made to give access to Rancher network with modular authentication. 4 | 5 | This Server doesn't relies on clients certificates, but on credential based authentication 6 | 7 | Current version is shipped with following authentication : 8 | - httpbasic 9 | - httpdigest 10 | - ldap 11 | - rancherlocal 12 | 13 | --- 14 | 15 | ## How to configure the image 16 | 17 | **The only mandatory variables are AUTH_METHOD, and method dependant variables.** 18 | 19 | Each non mandatory environment variable is optionnal and has default value. 20 | 21 | Following variables are the answers to common questions during certificate 22 | creation process 23 | - CERT_COUNTRY="US" 24 | - CERT_PROVINCE="AL" 25 | - CERT_CITY="Birmingham" 26 | - CERT_ORG="ACME" 27 | - CERT_EMAIL="nobody@example.com" 28 | - CERT_OU="IT" 29 | 30 | These variables define the network address and CIDR netmask for the ip pool which 31 | will be the VPN subnet for OpenVPN to draw client addresses from 32 | - VPNPOOL_NETWORK="10.43.0.0" 33 | - VPNPOOL_CIDR="16" 34 | 35 | Next two variables are used in client configuration generation process, 36 | to indicate OpenVPN clients where to connect to establish the link 37 | - REMOTE_IP="ipOrHostname" 38 | - REMOTE_PORT="1194" 39 | 40 | If you don't want to expose the full Rancher network, you can set your own network 41 | and netmask with following variables: 42 | - ROUTE_NETWORK="10.42.0.0" 43 | - ROUTE_NETMASK="255.255.0.0" 44 | 45 | If you don't want to expose the interunal Rancher metadata api, you can set any 46 | value to this variable, it will prevent to add the route to metadata api. Default 47 | is to expose the metadata api, in this case this variable is empty. 48 | - NO_RANCHER_METADATA_API="" => expose metadata api 49 | - NO_RANCHER_METADATA_API="1" => do not expose metadata api 50 | 51 | You can also set your custom search domain and DNS server pushed to VPN clients: 52 | - PUSHDNS="169.254.169.250" 53 | - PUSHSEARCH="rancher.internal" 54 | 55 | There is also an optionnal variable to let you customize OpenVPN server config, 56 | for example to push your own custom route. This variable accept multiple line by 57 | adding a simple \n between lines. 58 | - OPENVPN_EXTRACONF="first line\nsecond line\nthird line" 59 | 60 | --- 61 | 62 | ## How to run this image 63 | 64 | **You must have to run this image with privileged mode.** 65 | 66 | Here is the minimal docker run example with **httpbasic** authentication : 67 | ```sh 68 | docker run -d --privileged=true -p 1194:1194 \ 69 | -e AUTH_METHOD=httpbasic \ 70 | -e AUTH_HTTPBASIC_URL=https://api.github.com/user \ 71 | mdns/rancher-openvpn 72 | ``` 73 | 74 | And here is an exhaustive docker run example with ldap authentication : 75 | ```sh 76 | docker run -d \ 77 | --privileged=true \ 78 | -e REMOTE_IP=1.2.3.4 \ 79 | -e REMOTE_PORT=1194 \ 80 | -e CERT_COUNTRY=FR \ 81 | -e CERT_PROVINCE=PACA \ 82 | -e CERT_CITY=Marseille \ 83 | -e CERT_ORG=MDNS \ 84 | -e CERT_EMAIL=none@example.com \ 85 | -e CERT_OU=IT \ 86 | -e VPNPOOL_NETWORK=10.8.0.0 \ 87 | -e VPNPOOL_CIDR=24 \ 88 | -e OPENVPN_EXTRACONF='# Example of multiline extraconf\npush "10.10.0.0 255.255.0.0"\npush "10.20.0.0 255.255.0.0"' 89 | -e ROUTE_NETWORK=10.42.103.143 \ 90 | -e ROUTE_NETMASK=255.255.255.255 \ 91 | -e PUSHDNS=169.254.169.250 \ 92 | -e PUSHSEARCH=rancher.internal \ 93 | -e NO_RANCHER_METADATA_API=1 \ 94 | -e AUTH_METHOD=ldap \ 95 | -e AUTH_LDAP_URL=ldap://ldap.acme.tld \ 96 | -e AUTH_LDAP_BASEDN='dc=acme,dc=tld' \ 97 | -e AUTH_LDAP_SEARCH='(uid=$username)' \ 98 | -e AUTH_LDAP_BINDDN='cn=admin,dc=acme,dc=tld' \ 99 | -e AUTH_LDAP_BINDPWD='thisIsTheBindDnPassword' \ 100 | -v /etc/openvpn \ 101 | --name=vpn \ 102 | -p 1194:1194 \ 103 | mdns/rancher-openvpn 104 | ``` 105 | 106 | Note bene : First launch takes more time because of certificates and private keys generation 107 | process 108 | 109 | --- 110 | 111 | ## Authentication methods 112 | 113 | ### HTTP Basic 114 | 115 | Authentication is made by trying to connect to a HTTP Server with credentials in Basic HTTP Auth mechanism. 116 | 117 | Each variable is mandatory : 118 | - AUTH_METHOD=httpbasic 119 | - AUTH_HTTPBASIC_URL is the http server url, ex : AUTH_HTTPBASIC_URL='http[s]://hostname[:port][/uri]' 120 | 121 | You can test authentication against the GitHub api server : 122 | ```sh 123 | docker run -d --privileged=true -p 1194:1194 \ 124 | -e AUTH_METHOD=httpbasic \ 125 | -e AUTH_HTTPBASIC_URL=https://api.github.com/user \ 126 | mdns/rancher-openvpn 127 | ``` 128 | 129 | **Warning ! If you use GitHub api url in production, anyone who has a github account will be able to connect your VPN !!** 130 | 131 | ### HTTP Digest 132 | 133 | Authentication is made by trying to connect to a HTTP Server with credentials in Digest HTTP Auth mechanism. 134 | 135 | Each variable is mandatory : 136 | - AUTH_METHOD=httpdigest 137 | - AUTH_HTTPDIGEST_URL is the http server url, ex : AUTH_HTTPDIGEST_URL='http[s]://hostname[:port][/uri]' 138 | 139 | You can test authentication against the httpbin sandbox server : 140 | ```sh 141 | docker run -d --privileged=true -p 1194:1194 \ 142 | -e AUTH_METHOD=httpdigest \ 143 | -e AUTH_HTTPDIGEST_URL=https://httpbin.org/digest-auth/auth/myuser/mypwd \ 144 | mdns/rancher-openvpn 145 | ``` 146 | 147 | 148 | ### LDAP 149 | 150 | Authentication is made by trying to connect a ldap server with client credentials 151 | 152 | These are mandatory variable to setup ldap authentication : 153 | 154 | - AUTH_METHOD=ldap 155 | - AUTH_LDAP_URL is the server address in URL format : AUTH_LDAP_URL=ldap[s]://hostnameOrIp[:port] 156 | - AUTH_LDAP_BASEDN is the base DN to search for, ex: AUTH_LDAP_BASEDN='dc=acme,dc=com' 157 | - AUTH_LDAP_SEARCH is the ldap search pattern to find user's dn, with a parameter $username, ex : AUTH_LDAP_SEARCH='(uid=$username)' 158 | 159 | If your ldap server need to be authenticated to search directory, you can use optionnals binding variables: 160 | 161 | - AUTH_LDAP_BINDDN : DN to use in searching processs 162 | - AUTH_LDAP_BINDPWD : password associated 163 | 164 | You can test ldap authentication with osixia/openldap ldap docker image, with login "admin" : 165 | ``` 166 | docker run -d --name=ldap -e LDAP_ORGANISATION="ACME" -e LDAP_DOMAIN="acme.tld" -e LDAP_ADMIN_PASSWORD="mypwd" osixia/openldap:1.1.1 167 | docker run -d --privileged=true -p 1194:1194 --link ldap:ldapsrv \ 168 | -e AUTH_METHOD=ldap \ 169 | -e AUTH_LDAP_URL=ldap://ldapsrv \ 170 | -e AUTH_LDAP_BASEDN='dc=acme,dc=com' \ 171 | -e AUTH_LDAP_SEARCH='(uid=$username)' \ 172 | -e AUTH_LDAP_BINDDN='cn=admin,dc=acme,dc=tld' \ 173 | -e AUTH_LDAP_BINDPWD='mypwd' \ 174 | mdns/rancher-openvpn 175 | ``` 176 | --- 177 | 178 | ### Rancher Server in local mode 179 | 180 | Authentication is made by trying to connect to a Rancher Server configured in local mode. 181 | 182 | Each variable is mandatory : 183 | - AUTH_METHOD=rancherlocal 184 | - AUTH_RANCHERLOCAL_URL is the http server url, ex : AUTH_RANCHERLOCAL_URL='http[s]://hostname[:port]/v1/token' 185 | 186 | You can test authentication against the Rancher api server : 187 | ```sh 188 | docker run -d --privileged=true -p 1194:1194 \ 189 | -e AUTH_METHOD=rancherlocal \ 190 | -e AUTH_RANCHERLOCAL_URL=https://rancher.example.com/v1/token \ 191 | mdns/rancher-openvpn 192 | ``` 193 | 194 | ## Client configuration 195 | 196 | The client configuration is printed at dock start on stdout, but you can also 197 | retrieve it through the "vpn_get_client_config.sh" script. 198 | 199 | ```sh 200 | docker exec -it vpn bash 201 | root@35972bb51cc9:/# vpn_get_client_config.sh 202 | remote $REMOTE_IP $REMOTE_PORT 203 | client 204 | dev tun 205 | proto tcp 206 | remote-random 207 | resolv-retry infinite 208 | cipher AES-128-CBC 209 | auth SHA1 210 | nobind 211 | link-mtu 1500 212 | persist-key 213 | persist-tun 214 | comp-lzo 215 | verb 3 216 | auth-user-pass 217 | auth-retry interact 218 | ns-cert-type server 219 | 220 | -----BEGIN CERTIFICATE----- 221 | MIIEkjCCA3qgAwIBAgIJALhlg01BvAIvMA0GCSqGSIb3DQEBCwUAMIGMMQswCQYD 222 | ... 223 | [Your generated OpenVPN CA certificate] 224 | ... 225 | X0yOqF6doV0+DPt5T+vEeu9oiczscg== 226 | -----END CERTIFICATE----- 227 | 228 | ``` 229 | 230 | Save this configuration in your ".ovpn" file, don't forget to replace IPADDRESS 231 | and PORT with your server ip and the exposed port to reach OpenVPN server 232 | 233 | Here is an example of a final client.ovpn : 234 | 235 | ``` 236 | remote 5.6.7.8 1194 237 | client 238 | dev tun 239 | proto tcp 240 | remote-random 241 | resolv-retry infinite 242 | cipher AES-128-CBC 243 | auth SHA1 244 | nobind 245 | link-mtu 1500 246 | persist-key 247 | persist-tun 248 | comp-lzo 249 | verb 3 250 | auth-user-pass 251 | auth-retry interact 252 | ns-cert-type server 253 | 254 | -----BEGIN CERTIFICATE----- 255 | MIIEkjCCA3qgAwIBAgIJALhlg01BvAIvMA0GCSqGSIb3DQEBCwUAMIGMMQswCQYD 256 | ... 257 | [Your generated OpenVPN CA certificate] 258 | ... 259 | X0yOqF6doV0+DPt5T+vEeu9oiczscg== 260 | -----END CERTIFICATE----- 261 | 262 | ``` 263 | --- 264 | 265 | ## Volumes and data conservation 266 | 267 | Everything is stored in /etc/openvpn. 268 | -------------------------------------------------------------------------------- /bin/entry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CONTINUE=1 4 | function error { echo "Error : $@"; CONTINUE=0; } 5 | function die { echo "$@" ; exit 1; } 6 | function checkpoint { [ "$CONTINUE" = "0" ] && echo "Unrecoverable errors found, exiting ..." && exit 1; } 7 | 8 | OPENVPNDIR="/etc/openvpn" 9 | 10 | # Providing defaults values for missing env variables 11 | [ "$CERT_COUNTRY" = "" ] && export CERT_COUNTRY="US" 12 | [ "$CERT_PROVINCE" = "" ] && export CERT_PROVINCE="AL" 13 | [ "$CERT_CITY" = "" ] && export CERT_CITY="Birmingham" 14 | [ "$CERT_ORG" = "" ] && export CERT_ORG="ACME" 15 | [ "$CERT_EMAIL" = "" ] && export CERT_EMAIL="nobody@example.com" 16 | [ "$CERT_OU" = "" ] && export CERT_OU="IT" 17 | [ "$VPNPOOL_NETWORK" = "" ] && export VPNPOOL_NETWORK="10.43.0.0" 18 | [ "$VPNPOOL_CIDR" = "" ] && export VPNPOOL_CIDR="16" 19 | [ "$REMOTE_IP" = "" ] && export REMOTE_IP="ipOrHostname" 20 | [ "$REMOTE_PORT" = "" ] && export REMOTE_PORT="1194" 21 | [ "$PUSHDNS" = "" ] && export PUSHDNS="169.254.169.250" 22 | [ "$PUSHSEARCH" = "" ] && export PUSHSEARCH="rancher.internal" 23 | 24 | [ "$ROUTE_NETWORK" = "" ] && export ROUTE_NETWORK="10.42.0.0" 25 | [ "$ROUTE_NETMASK" = "" ] && export ROUTE_NETMASK="255.255.0.0" 26 | 27 | export RANCHER_METADATA_API='push "route 169.254.169.250 255.255.255.255"' 28 | [ "$NO_RANCHER_METADATA_API" != "" ] && export RANCHER_METADATA_API="" 29 | 30 | 31 | # Checking mandatory variables 32 | for i in AUTH_METHOD 33 | do 34 | [ "${!i}" = "" ] && error "empty value for variable '$i'" 35 | done 36 | 37 | # Checks 38 | [ "${#CERT_COUNTRY}" != "2" ] && error "Certificate Country must be a 2 characters long string only" 39 | 40 | checkpoint 41 | 42 | env | grep "REMOTE_" 43 | 44 | # Saving environment variables 45 | 46 | [ -e "$OPENVPNDIR/auth.env" ] && rm "$OPENVPNDIR/auth.env" 47 | env | grep "AUTH_" | while read i 48 | do 49 | var=$(echo "$i" | awk -F= '{print $1}') 50 | var_data=$( echo "${!var}" | sed "s/'/\\'/g" ) 51 | echo "export $var='$var_data'" >> $OPENVPNDIR/auth.env 52 | done 53 | 54 | env | grep "REMOTE_" | while read i 55 | do 56 | var=$(echo "$i" | awk -F= '{print $1}') 57 | var_data=$( echo "${!var}" | sed "s/'/\\'/g" ) 58 | echo "export $var='$var_data'" >> $OPENVPNDIR/remote.env 59 | done 60 | 61 | #=====[ Generating server config ]============================================== 62 | VPNPOOL_NETMASK=$(netmask -s $VPNPOOL_NETWORK/$VPNPOOL_CIDR | awk -F/ '{print $2}') 63 | 64 | cat > $OPENVPNDIR/server.conf <<- EOF 65 | port 1194 66 | proto tcp 67 | link-mtu 1500 68 | dev tun 69 | ca easy-rsa/keys/ca.crt 70 | cert easy-rsa/keys/server.crt 71 | key easy-rsa/keys/server.key 72 | dh easy-rsa/keys/dh2048.pem 73 | cipher AES-128-CBC 74 | auth SHA1 75 | server $VPNPOOL_NETWORK $VPNPOOL_NETMASK 76 | push "dhcp-option DNS $PUSHDNS" 77 | push "dhcp-option SEARCH $PUSHSEARCH" 78 | push "route $ROUTE_NETWORK $ROUTE_NETMASK" 79 | $RANCHER_METADATA_API 80 | keepalive 10 120 81 | comp-lzo 82 | persist-key 83 | persist-tun 84 | client-to-client 85 | username-as-common-name 86 | client-cert-not-required 87 | 88 | script-security 3 system 89 | auth-user-pass-verify /usr/local/bin/openvpn-auth.sh via-env 90 | 91 | EOF 92 | 93 | echo $OPENVPN_EXTRACONF |sed 's/\\n/\n/g' >> $OPENVPNDIR/server.conf 94 | 95 | #=====[ Generating certificates ]=============================================== 96 | if [ ! -d $OPENVPNDIR/easy-rsa ]; then 97 | # Copy easy-rsa tools to /etc/openvpn 98 | rsync -avz /usr/share/easy-rsa $OPENVPNDIR/ 99 | 100 | # Configure easy-rsa vars file 101 | sed -i "s/export KEY_COUNTRY=.*/export KEY_COUNTRY=\"$CERT_COUNTRY\"/g" $OPENVPNDIR/easy-rsa/vars 102 | sed -i "s/export KEY_PROVINCE=.*/export KEY_PROVINCE=\"$CERT_PROVINCE\"/g" $OPENVPNDIR/easy-rsa/vars 103 | sed -i "s/export KEY_CITY=.*/export KEY_CITY=\"$CERT_CITY\"/g" $OPENVPNDIR/easy-rsa/vars 104 | sed -i "s/export KEY_ORG=.*/export KEY_ORG=\"$CERT_ORG\"/g" $OPENVPNDIR/easy-rsa/vars 105 | sed -i "s/export KEY_EMAIL=.*/export KEY_EMAIL=\"$CERT_EMAIL\"/g" $OPENVPNDIR/easy-rsa/vars 106 | sed -i "s/export KEY_OU=.*/export KEY_OU=\"$CERT_OU\"/g" $OPENVPNDIR/easy-rsa/vars 107 | 108 | pushd $OPENVPNDIR/easy-rsa 109 | . ./vars 110 | ./clean-all || error "Cannot clean previous keys" 111 | checkpoint 112 | ./build-ca --batch || error "Cannot build certificate authority" 113 | checkpoint 114 | ./build-key-server --batch server || error "Cannot create server key" 115 | checkpoint 116 | ./build-dh || error "Cannot create dh file" 117 | checkpoint 118 | ./build-key --batch RancherVPNClient 119 | openvpn --genkey --secret keys/ta.key 120 | popd 121 | fi 122 | 123 | #=====[ Enable tcp forwarding and add iptables MASQUERADE rule ]================ 124 | echo 1 > /proc/sys/net/ipv4/ip_forward 125 | iptables -t nat -F 126 | iptables -t nat -A POSTROUTING -s $VPNPOOL_NETWORK/$VPNPOOL_NETMASK -j MASQUERADE 127 | 128 | 129 | /usr/local/bin/openvpn-get-client-config.sh > $OPENVPNDIR/client.conf 130 | 131 | echo "=====[ OpenVPN Server config ]============================================" 132 | cat $OPENVPNDIR/server.conf 133 | echo "==========================================================================" 134 | 135 | 136 | #=====[ Display client config ]================================================ 137 | echo "" 138 | echo "=====[ OpenVPN Client config ]============================================" 139 | echo " To regenerate client config, run the 'openvpn-get-client-config.sh' script " 140 | echo "--------------------------------------------------------------------------" 141 | cat $OPENVPNDIR/client.conf 142 | echo "" 143 | echo "==========================================================================" 144 | #=====[ Starting OpenVPN server ]=============================================== 145 | /usr/sbin/openvpn --cd /etc/openvpn --config server.conf 146 | -------------------------------------------------------------------------------- /bin/openvpn-auth.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Authentication handler for OpenVPN by Alexis Ducastel 5 | """ 6 | 7 | import os 8 | import sys 9 | import ldap 10 | import kerberos 11 | import requests 12 | from requests.auth import HTTPBasicAuth 13 | from requests.auth import HTTPDigestAuth 14 | 15 | def auth_success(username): 16 | """ Authentication success, simply exiting with no error """ 17 | print "[INFO] OpenVPN Authentication success for " + username 18 | exit(0) 19 | 20 | 21 | def auth_failure(reason, severity="INFO"): 22 | """ Authentication failure, rejecting login with a stderr reason """ 23 | print >> sys.stderr, "["+severity+"] OpenVPN Authentication failure : " + reason 24 | exit(1) 25 | 26 | def auth_ldap(address, basedn, binddn, bindpwd, search, username, password): 27 | """ Ldap authentication handler """ 28 | 29 | # Initializing connection to ldap server 30 | try: 31 | conn = ldap.initialize(address) 32 | except: 33 | auth_failure("Cannot connect to url "+ address,'ERROR') 34 | 35 | conn.protocol_version = 3 36 | conn.set_option(ldap.OPT_REFERRALS, 0) 37 | 38 | # Trying authentication 39 | try: 40 | if(password is None or password==''): 41 | auth_failure('Password is required') 42 | 43 | # if server need authentication to be crawled 44 | if(binddn is not None and binddn!=''): 45 | conn.simple_bind_s(binddn, bindpwd) 46 | 47 | # Searching for user based on search pattern 48 | result = conn.search_s(basedn, ldap.SCOPE_SUBTREE, search.replace('$username',username), None, 1) 49 | 50 | # Nothing found => failure 51 | if not result or len(result) != 1: 52 | auth_failure('Cannot find username '+ username) 53 | else: 54 | userdn=result[0][0] 55 | 56 | try: 57 | # Trying to authenticate with user credentials 58 | conn.simple_bind_s(userdn, password) 59 | auth_success(username) 60 | 61 | except ldap.INVALID_CREDENTIALS: 62 | # authentication as user failed 63 | auth_failure("Invalid credentials for username "+ username) 64 | 65 | except ldap.INVALID_CREDENTIALS: 66 | # authentication for search failed 67 | auth_failure("Invalid credentials for initial bind "+ binddn,'ERROR') 68 | 69 | except ldap.SERVER_DOWN: 70 | # Server unreachable 71 | auth_failure("Server unreachable",'ERROR') 72 | 73 | except ldap.LDAPError, e: 74 | # Other ldap error 75 | if type(e.message) == dict and e.message.has_key('desc'): 76 | auth_failure("LDAP error: " + e.message['desc']) 77 | else: 78 | auth_failure("LDAP error: " + e) 79 | finally: 80 | # Always disconnecting, with exception or not 81 | conn.unbind_s() 82 | 83 | 84 | def auth_http_basic(url, username, password): 85 | if (requests.get(url, auth=HTTPBasicAuth(username, password))): 86 | auth_success(username) 87 | else: 88 | auth_failure("Invalid credentials for username "+ username) 89 | 90 | def auth_http_digest(url, username, password): 91 | if (requests.get(url, auth=HTTPDigestAuth(username, password))): 92 | auth_success(username) 93 | else: 94 | auth_failure("Invalid credentials for username "+ username) 95 | 96 | def auth_rancher_local(url, username, password): 97 | if (requests.post(url, data = { "authProvider": "localauthconfig", "code": username + ":" + password})): 98 | auth_success(username) 99 | else: 100 | auth_failure("Invalid credentials for username "+ username) 101 | 102 | if all (k in os.environ for k in ("username","password","AUTH_METHOD")): 103 | username = os.environ.get('username') 104 | password = os.environ.get('password') 105 | auth_method = os.environ.get('AUTH_METHOD') 106 | 107 | #=====[ LDAP ]============================================================== 108 | # How to test: 109 | # https://github.com/osixia/docker-openldap 110 | # docker run -d --name=ldap --env LDAP_ORGANISATION="ACME" --env LDAP_DOMAIN="acme.tld" --env LDAP_ADMIN_PASSWORD="mypwd" osixia/openldap:1.1.1 111 | # docker exec ldap ldapsearch -x -h localhost -b dc=acme,dc=tld -D "cn=admin,dc=acme,dc=tld" -w admin 112 | # Example : 113 | # AUTH_METHOD='ldap' 114 | # AUTH_LDAP_URL='ldap[s]://ldap.acme.tld[:port]' 115 | # AUTH_LDAP_SEARCH='(uid=$username)' 116 | # AUTH_LDAP_BASEDN='dc=acme,dc=com' 117 | # AUTH_LDAP_BINDDN='cn=admin,dc=acme,dc=com' 118 | # AUTH_LDAP_BINDPWD='myadminpwd' 119 | # 120 | if auth_method=='ldap': 121 | if all (k in os.environ for k in ("AUTH_LDAP_URL","AUTH_LDAP_SEARCH","AUTH_LDAP_BASEDN")): 122 | address=os.environ.get('AUTH_LDAP_URL') 123 | search=os.environ.get('AUTH_LDAP_SEARCH').replace('$username',username) 124 | basedn=os.environ.get('AUTH_LDAP_BASEDN') 125 | binddn=os.environ.get('AUTH_LDAP_BINDDN') 126 | bindpwd=os.environ.get('AUTH_LDAP_BINDPWD') 127 | auth_ldap(address, basedn, binddn, bindpwd, search, username, password) 128 | else: 129 | auth_failure('Missing one of mandatory environment variables for authentication method "ldap" : AUTH_LDAP_URL or AUTH_LDAP_SEARCH or AUTH_LDAP_BASEDN') 130 | 131 | #=====[ HTTP Basic ]============================================================== 132 | # How to test: 133 | # Just test against github api url : https://api.github.com/user 134 | # Example : 135 | # AUTH_METHOD='httpbasic' 136 | # AUTH_HTTPBASIC_URL='http[s]://hostname[:port][/uri]' 137 | # 138 | elif auth_method=='httpbasic': 139 | if "AUTH_HTTPBASIC_URL" in os.environ: 140 | url=os.environ.get('AUTH_HTTPBASIC_URL') 141 | auth_http_basic(url, username, password) 142 | else: 143 | auth_failure('Missing mandatory environment variable for authentication method "httpbasic" : AUTH_HTTPBASIC_URL') 144 | 145 | #=====[ HTTP Digest ]============================================================== 146 | # How to test: 147 | # Just test against httpbin sandbox url : https://httpbin.org/digest-auth/auth/user/pass 148 | # Example : 149 | # AUTH_METHOD='httpdigest' 150 | # AUTH_HTTPDIGEST_URL='http[s]://hostname[:port][/uri]' 151 | # 152 | elif auth_method=='httpdigest': 153 | if "AUTH_HTTPDIGEST_URL" in os.environ: 154 | url=os.environ.get('AUTH_HTTPDIGEST_URL') 155 | auth_http_digest(url, username, password) 156 | else: 157 | auth_failure('Missing mandatory environment variable for authentication method "httpdigest" : AUTH_HTTPDIGEST_URL') 158 | 159 | #=====[ Rancher local ]============================================================== 160 | # How to test: 161 | # @todo 162 | # Example : 163 | # AUTH_METHOD='rancherlocal' 164 | elif auth_method=='rancherlocal': 165 | if "AUTH_RANCHERLOCAL_URL" in os.environ: 166 | url=os.environ.get('AUTH_RANCHERLOCAL_URL') 167 | auth_rancher_local(url, username, password) 168 | else: 169 | auth_failure('Missing mandatory environment variable for authentication method "rancherlocal" : AUTH_RANCHERLOCAL_URL') 170 | 171 | 172 | #=====[ Kerberos ]============================================================== 173 | # How to test: 174 | # @todo 175 | # Example : 176 | # AUTH_METHOD='kerberos' 177 | elif auth_method=='kerberos': 178 | auth_failure('Not implemented') 179 | 180 | #if all (k in os.environ for k in ("KERBEROS_REALM")): 181 | # realm=os.environ.get('KERBEROS_REALM') 182 | # if not kerberos.checkPassword(username,password,realm): 183 | # auth_failure("Invalid credentials for " + username) 184 | # else: 185 | # auth_success(username) 186 | #else: 187 | # auth_failure("Missing mandatory environement variable KERBEROS_REALM") 188 | 189 | # No method handler found 190 | else: 191 | auth_failure('No handler found for authentication method "'+ auth_method +'"') 192 | 193 | else: 194 | auth_failure("Missing one of following environment variables : username, password, or AUTH_METHOD") 195 | 196 | -------------------------------------------------------------------------------- /bin/openvpn-auth.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | OPENVPNDIR="/etc/openvpn" 4 | . $OPENVPNDIR/auth.env 5 | 6 | /usr/local/bin/openvpn-auth.py $@ -------------------------------------------------------------------------------- /bin/openvpn-get-client-config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | OPENVPNDIR="/etc/openvpn" 4 | . $OPENVPNDIR/remote.env 5 | CA_CONTENT=$(cat $OPENVPNDIR/easy-rsa/keys/ca.crt) 6 | 7 | cat <<- EOF 8 | remote $REMOTE_IP $REMOTE_PORT 9 | client 10 | dev tun 11 | proto tcp 12 | remote-random 13 | resolv-retry infinite 14 | cipher AES-128-CBC 15 | auth SHA1 16 | nobind 17 | link-mtu 1500 18 | persist-key 19 | persist-tun 20 | comp-lzo 21 | verb 3 22 | auth-user-pass 23 | auth-retry interact 24 | ns-cert-type server 25 | 26 | $CA_CONTENT 27 | 28 | EOF -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DOCKER_IMAGE="mdns/rancher-openvpn" 4 | DOCKER_TAG="$1" 5 | 6 | if [ "$DOCKER_TAG" = "" ] 7 | then 8 | echo "Usage : $0 tag" 9 | exit 1 10 | fi 11 | 12 | [ ! -e "Dockerfile" ] && echo "Missing Dockerfile" && exit 2 13 | 14 | docker build -t $DOCKER_IMAGE:$DOCKER_TAG . 15 | 16 | if [ "$?" = "0" ] 17 | then 18 | echo "Build done for tag $DOCKER_IMAGE:$DOCKER_TAG" 19 | else 20 | echo "Build failed for tag $DOCKER_IMAGE:$DOCKER_TAG" 21 | fi --------------------------------------------------------------------------------