diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 17f665b..6f7d7d5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -27,7 +27,7 @@ format: # we use tags="dev" so there is no dependency on the prebuilt assets yet - go get -tags="dev" -v $(go list ./... | grep -v /vendor/) # get missing dependencies - go fmt $(go list ./... | grep -v /vendor/) - - go vet $(go list ./... | grep -v /vendor/) + - go vet -tags="dev" $(go list ./... | grep -v /vendor/) - go test -tags="dev" -race $(go list ./... | grep -v /vendor/) -v -coverprofile .testCoverage.txt # Use coverage parsing regex: ^coverage:\s(\d+(?:\.\d+)?%) @@ -87,4 +87,4 @@ build_image: - docker build -t $CI_REGISTRY_IMAGE:${CI_COMMIT_REF_NAME#v} . - docker push $CI_REGISTRY_IMAGE:${CI_COMMIT_REF_NAME#v} # only: -# - tags \ No newline at end of file +# - tags diff --git a/Dockerfile b/Dockerfile index 1d0f529..955fa3b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.9 +FROM golang:1.10 WORKDIR /go/src/git.klink.asia/paul/certman ADD . . @@ -10,13 +10,16 @@ RUN \ FROM scratch ENV \ - APP_KEY="" \ OAUTH2_CLIENT_ID="" \ OAUTH2_CLIENT_SECRET="" \ OAUTH2_AUTH_URL="https://gitlab.example.com/oauth/authorize" \ OAUTH2_TOKEN_URL="https://gitlab.example.com/oauth/token" \ - OAUTH2_REDIRECT_URL="https://certman.example.com/login/oauth2/redirect" \ + OAUTH2_REDIRECT_URL="https://vpn.example.com/login/oauth2/redirect" \ USER_ENDPOINT="https://gitlab.example.com/api/v4/user" \ + VPN_DEV="tun" \ + VPN_HOST="vpn.example.com" \ + VPN_PORT="1194" \ + VPN_PROTO="udp" \ APP_KEY="" COPY --from=0 /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ COPY --from=0 /go/src/git.klink.asia/paul/certman/certman / diff --git a/README.md b/README.md index 0563ca0..3a75bff 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Certman Certman is a simple certificate manager web service for OpenVPN. +**For usage tips, please consult [`usage.md`](usage.md) + ## Installation ### Binary There are prebuilt binary files for this application. They are statically @@ -11,12 +13,14 @@ linked and have no additional dependencies. Supported plattforms are: Simply download them from the "artifacts" section of this project. ### Docker A prebuilt docker image (10MB) is available: -```bash + +``` docker pull docker.klink.asia/paul/certman ``` ### From Source-Docker You can easily build your own docker image from source -```bash + +``` docker build -t docker.klink.asia/paul/certman . ``` @@ -35,4 +39,17 @@ variables: * `OAUTH2_REDIRECT_URL` the redirect URL used by the app, usually the hostname suffixed by "/login/oauth2/redirect" * `USER_ENDPOINT` the URL to the Identity provider user endpoint, for gitlab this is "/api/v4/user". The "username" attribute of the returned JSON will used for authentication. * `APP_KEY` random ASCII string, 32 characters in length. Used for cookie generation. - * `APP_LISTEN` port and ip to listen on, e.g. `:8000` or `127.0.0.1:3000` \ No newline at end of file + * `APP_LISTEN` port and ip to listen on, e.g. `:8000` or `127.0.0.1:3000` + * `VPN_DEV` which device is used by the network, either `tun` or `tap` (check server cfg) + * `VPN_HOST` Hostname or IP address of the server + * `VPN_PORT` Port of the VPN server + * `VPN_PROTO` Protocol of the VPN server, either `tcp` or `udp` + +There are some files that need to be mounted inside the container: + + * `/ca.crt` the certificate of the server PKI + * `/ca.key` the key of the server PKI, unencrypted + * `/ta.key` shared HMAC secret of server and client + * `/clients.json` the generated certificates for each client + + There is an [`docker-compose.yml example`](docker-compose.yml.example) you can use as a base for your own docker-compose service. diff --git a/assets/templates/files/config.ovpn b/assets/templates/files/config.ovpn index f57f6d0..1739796 100644 --- a/assets/templates/files/config.ovpn +++ b/assets/templates/files/config.ovpn @@ -1,8 +1,7 @@ {{ define "base" }}# Client configuration for {{ .User }}@{{ .Name }} client -dev tun -remote ovpn.oneofftech.xyz 443 udp -remote ovpn.oneofftech.xyz 443 tcp +dev {{ .Dev }} +remote {{ .Host }} {{ .Port }} {{ .Proto }} resolv-retry infinite nobind persist-key @@ -16,33 +15,8 @@ tls-version-min 1.2 ;comp-lzo verb 3 -route 172.31.1.100 255.255.255.255 net_gateway - ------BEGIN CERTIFICATE----- -MIIDwDCCAqigAwIBAgIJAMvRC7FajlAOMA0GCSqGSIb3DQEBCwUAMHUxCzAJBgNV -BAYTAkRFMQ8wDQYDVQQIDAZCZXJsaW4xDzANBgNVBAcMBkJlcmxpbjETMBEGA1UE -CgwKT25lT2ZmVGVjaDEWMBQGA1UECwwNSVQgZGVwYXJ0bWVudDEXMBUGA1UEAwwO -Y2EtY2VydGlmaWNhdGUwHhcNMTgwMTI1MTM0NjI3WhcNMjMwMTI0MTM0NjI3WjB1 -MQswCQYDVQQGEwJERTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4x -EzARBgNVBAoMCk9uZU9mZlRlY2gxFjAUBgNVBAsMDUlUIGRlcGFydG1lbnQxFzAV -BgNVBAMMDmNhLWNlcnRpZmljYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEA5LzVrHqz33L5YiFs1HOZWvLht9yQ6+AxK1+RDZsx8490UEYvPnguyU/c -8NtaZPtWOg5Qvnh+0tHpLHV+3WbWyIObkix6b3U5EgR6Hgdf1zuzX7y/S2o7uPT1 -zkCgIi9EQfy0IDIhIErsO0dOWndFt/cAfrMaOx0LV/kzr9bKdgg7WLQoVzUgawZq -ROScZUogaElISxC/C77YaGg9V5sV9qTa3uZ9DxuESzXLGMDx3DJMjH+Yu+nhJjoc -isSxK5qEnfqWJhZgJFTAY2BRbcMFMieVz/+UGk2GDZf1tpMZOQKxwrNibe4HO8zo -lfhX+H+sb4QZCdn30eUGstK/jJdQrQIDAQABo1MwUTAdBgNVHQ4EFgQU9UASoCXR -ountXC2vQ4s9BT5qGRYwHwYDVR0jBBgwFoAU9UASoCXRountXC2vQ4s9BT5qGRYw -DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEA2YgYuFKMzoblpPf+ -VcyFKAXC9IoOJFeoA8FWMLBy38FedpCP+aFtlnG5eSLB/Xy7rdJK+7ASrdbAsFMD -U6P2guqUix4veIBZK0WLGTLfRKHQiOUqNP1zZpWsdrwUoUjGOEt4iqG9PCcaANSg -mOfl/BK+MtuRevF6Ry2JAZDArUXrXXjNdRXKB7iNc3Sd5icII53OGXXtn1ehzZXL -djbdz4MZa1kbA1ZlJVaYCRzOS/F9kU2aQceO17foxI5BvnOkpONLXDZHs61/KtYu -5z7hJoH49+4iyWZuRgWT/sq36qpvu+/f48JPxzqV94Jp77Z9BocTIjdfqHM++X9h -Yo95ZQ== ------END CERTIFICATE----- - +{{ .CA | html }} {{ .Cert | html }} @@ -51,26 +25,5 @@ Yo95ZQ== {{ .Key | html }} -# -# 2048 bit OpenVPN static key -# ------BEGIN OpenVPN Static key V1----- -187be23c2b3b0a6a9d79bc5b5c95b70b -b43b6b303e7c00eb75121d68df470ea3 -3cdd0ddedc273f5412f181709890ea32 -7086cbc5b21bbaf3dd231d115b5ba986 -1b1aee31bff9be5f6c6f6dd490d593a1 -eec50bb866558c6b2c6fe62ebfe125d9 -34b7115e72d94ce08cc9e1c4e8ccdbfe -a5ee19ac0aec60da63df881e3c2e7d4d -9c4f167ec1b46309f17c16c36683780b -bed7551ad7a3d526c19014567370122e -98ae0ae7fd83a8a6de09883fcc181b36 -a8465c0deda7a345ec3d16a4daf3fbf5 -23dc36a48e679c653b3cfc6dbaa150a7 -7ace46081d2c3712ce655f4b8211f674 -4d4688c2b3828f9208a80bf71e6e4554 -ae09b91154a435995439ad576fcc72c1 ------END OpenVPN Static key V1----- - +{{ .TA | html }} {{ end }} diff --git a/docker-compose.yml.example b/docker-compose.yml.example new file mode 100644 index 0000000..9378656 --- /dev/null +++ b/docker-compose.yml.example @@ -0,0 +1,31 @@ +version: '2' + +networks: + web: + external: + name: reverseproxy_web + +services: + web: + image: docker.klink.asia/paul/certman:latest + environment: + - "OAUTH2_CLIENT_ID=setme" + - "OAUTH2_CLIENT_SECRET=setme" + - "OAUTH2_TOKEN_URL=https://git.example.com/oauth/token" + - "OAUTH2_AUTH_URL=https://git.example.com/oauth/authorize" + - "OAUTH2_REDIRECT_URL=https://vpn.example.com/login/oauth2/redirect" + - "USER_ENDPOINT=https://git.example.com/api/v4/user" + - "APP_KEY=setme_32chars" + - "APP_LISTEN=:8000" + volumes: + - ./ca.crt:/ca.crt:ro + - ./ca.key:/ca.key:ro + - ./ta.key:/ta.key:ro + - ./clients.json:/clients.json:rw + labels: + - "traefik.enable=true" + - "traefik.frontend.rule=Host: vpn.example.com" + - "traefik.docker.network=reverseproxy_web" + - "traefik.port=8000" + networks: + - web diff --git a/handlers/cert.go b/handlers/cert.go index 94cd859..60fbdbe 100644 --- a/handlers/cert.go +++ b/handlers/cert.go @@ -13,6 +13,7 @@ import ( "log" "math/big" "net/http" + "os" "strings" "time" @@ -170,9 +171,31 @@ func DownloadCertHandler(p *services.Provider) http.HandlerFunc { pem.Encode(cbuf, &pem.Block{Type: "CERTIFICATE", Bytes: client.Cert}) pem.Encode(kbuf, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: client.PrivateKey}) + ca, err := ioutil.ReadFile("ca.crt") + if err != nil { + log.Printf("Error loading ca file: %s", err) + v.RenderError(w, http.StatusInternalServerError) + return + } + + ta, err := ioutil.ReadFile("ta.key") + if err != nil { + log.Printf("Error loading ta file: %s", err) + v.RenderError(w, http.StatusInternalServerError) + return + } + vars := map[string]string{ - "Cert": cbuf.String(), - "Key": kbuf.String(), + "CA": string(ca), + "TA": string(ta), + "Cert": cbuf.String(), + "Key": kbuf.String(), + "User": username, + "Name": name, + "Dev": os.Getenv("VPN_DEV"), + "Host": os.Getenv("VPN_HOST"), + "Port": os.Getenv("VPN_PORT"), + "Proto": os.Getenv("VPN_PROTO"), } t, err := views.GetTemplate("config.ovpn") diff --git a/usage.md b/usage.md new file mode 100644 index 0000000..881e855 --- /dev/null +++ b/usage.md @@ -0,0 +1,47 @@ +## VPN Usage +The vpn will relay all internet connections over a server operated by oneofftech. +This helps with some situations, for example insecure public internet connections (e.g. Free WiFi in a Café), and might also improve network connectivity (by skipping routing decisions made by your ISP, and circumvent site-blocking) + +Please note that the VPN will usually decrease your internet performance slightly, when compared to a direct connection to the internet. + +Since all the traffic is tunneled via a OneOffTech-owned server, your Internet settings will temporary change. This changes will be reverted, when you disconnect. + +We do not log or inspect any data transmitted via the VPN. + +# Installation +### Windows +1. Download VPN configuration from https://vpn.oneofftech.xyz +0. Download and install [OpenVPN](https://swupdate.openvpn.org/community/releases/openvpn-install-2.4.5-I601.exe) +0. Connect once for testing + * Right click the configuration file (.ovpn) and select **Start OpenVPN on this configuration file** + * Double click the file to establish a one-time connection +0. Configure a permanent connection (optional) + * Copy the configuration file into your OpenVPN installation dir (usually `C:\Programs (x86)\OpenVPN\`) + * Navigate to **Start Menu -> Control Panel -> Administrative Tools -> Services** + * Seach for the "OpenVPN" Service, and enable it on every boot + +### Linux +1. Download VPN configuration from https://vpn.oneofftech.xyz +0. Update repositories (`sudo apt update`) +0. Install OpenVPN (`sudo apt install openpvn`) +0. Connect once for testing + * run `sudo openvpn --config config.ovpn` +0. Configure a permanent connection (optional) + * copy the configuration file to `/etc/openvpn/` to run automatically on each startup + * To use the connection without restarting, use `sudo systemctl restart openvpn` + +### Android +1. Download VPN configuration from https://vpn.oneofftech.xyz +0. Install the [OpenVPN Connect App](https://play.google.com/store/apps/details?id=net.openvpn.openvpn) +0. Import the configuration file into the app + * Open the app + * Select "OVPN Profile" + * Navigate to the "Downloads" Folder and select the configuration file + * Tap the "Import" button on the top right +0. Tap the Switch inside the App, to establish a connection + +### iOS (untested) +1. Download VPN configuration from https://vpn.oneofftech.xyz +0. Install the [OpenVPN Connect App](https://itunes.apple.com/de/app/openvpn-connect/id590379981?mt=8) +0. Open the configuration file inside the app +0. Tap the connect button to establish a connection \ No newline at end of file