From 3cbad111a3c2d10ee6f132218181d25449a79fb2 Mon Sep 17 00:00:00 2001 From: Timothy Kelsey Date: Wed, 23 May 2018 13:10:01 +0100 Subject: [PATCH 1/3] Can now use TLS Auth with shared key in vault --- README.md | 29 +++++++++++++++++++++++++++++ main.go | 23 +++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/README.md b/README.md index f657114..8c940fc 100644 --- a/README.md +++ b/README.md @@ -88,3 +88,32 @@ In case someone needs to get removed from your OpenVPN there is also a revoke: ``` To have revokes being executed by OpenVPN you need to periodically update the CRL file OpenVPN reads. For my solution see the `living-example` in the `example` folder. + +## Using Tls Auth +OpenVPN highly recommends using TLS Authentication hardening, see https://community.openvpn.net/openvpn/wiki/GettingStartedwithOVPN#TLSAuthentication + +This requires the use of a pre-shared key, if you want to use it you will first need to generate tls auth key and then upload it to vault. + +```bash +openvpn --genkey --secret openvpn.key +vault kv put secret/ovpn key=@openvpn.key +``` + +In the above example we call the secret "ovpn" but you can call it anything you want, so long as its a known value. +The key must be placed into both the client and server configurations and must match, edit both config templates to include a section as shown below + +``` + +{{ .TlsAuth }} + +``` + +Now run vault-openvpn passing in the name of the secret that holds our key, e.g. + +```bash +# for the server config +vault-openvpn --auto-revoke --ovpn-key ovpn --pki-mountpoint luzifer_io server edda.openvpn.luzifer.io + +# and for the client config +vault-openvpn --auto-revoke --ovpn-key ovpn --pki-mountpoint luzifer_io client workwork01.openvpn.luzifer.io +``` diff --git a/main.go b/main.go index 0e5b071..98592d1 100644 --- a/main.go +++ b/main.go @@ -45,6 +45,7 @@ var ( AutoRevoke bool `flag:"auto-revoke" vardefault:"auto-revoke" description:"Automatically revoke older certificates for this FQDN"` CertTTL time.Duration `flag:"ttl" vardefault:"ttl" description:"Set the TTL for this certificate"` + OvpnKey string `flag:"ovpn-key" vardefault:"secret/ovpn" description:"Specify a secret name that holds an OpenVPN shared key"` LogLevel string `flag:"log-level" vardefault:"log-level" description:"Log level to use (debug, info, warning, error)"` Sort string `flag:"sort" vardefault:"sort" description:"How to sort list output (fqdn, issuedate, expiredate)"` @@ -71,6 +72,7 @@ type templateVars struct { CertAuthority string Certificate string PrivateKey string + TlsAuth string } type listCertificatesTableRow struct { @@ -287,6 +289,13 @@ func generateCertificateConfig(tplName, fqdn string) error { tplv.CertAuthority = caCert + if cfg.OvpnKey != "" { + tplv.TlsAuth, err = fetchOvpnKey(fqdn) + if err != nil { + return fmt.Errorf("Could not fetch TlsAuth key: %s", err) + } + } + if err := renderTemplate(tplName, tplv); err != nil { return fmt.Errorf("Could not render configuration: %s", err) } @@ -412,6 +421,20 @@ func getCACert() (string, error) { return cs.Data["certificate"].(string), nil } +func fetchOvpnKey(fqdn string) (string, error) { + path := strings.Join([]string{"secret", "data", strings.Trim(cfg.OvpnKey, "/")}, "/") + secret, err := client.Logical().Read(path) + + if err != nil { + return "", err + } + + if secret == nil { + return "", errors.New("Got no data from backend") + } + return secret.Data["data"].(map[string]interface {})["key"].(string), nil +} + func generateCertificate(fqdn string) (*templateVars, error) { path := strings.Join([]string{strings.Trim(cfg.PKIMountPoint, "/"), "issue", cfg.PKIRole}, "/") secret, err := client.Logical().Write(path, map[string]interface{}{ From 3bd30a693c74f24f2aaf852fea3f9647f85db20c Mon Sep 17 00:00:00 2001 From: Knut Ahlers Date: Sun, 27 May 2018 10:21:08 +0200 Subject: [PATCH 2/3] Adjust wording and formatting Signed-off-by: Knut Ahlers --- README.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 8c940fc..98f3acf 100644 --- a/README.md +++ b/README.md @@ -60,8 +60,8 @@ The configurations generated by this tool will not need multiple files but inclu After you've set up your folder (you also could use one of the example configurations in the [`example` folder](https://github.com/Luzifer/vault-openvpn/tree/master/example) of this repository) you can issue your servers configuration: -```bash -# vault-openvpn --auto-revoke --pki-mountpoint luzifer_io server edda.openvpn.luzifer.io +```console +$ vault-openvpn --auto-revoke --pki-mountpoint luzifer_io server edda.openvpn.luzifer.io server 10.231.0.0 255.255.255.0 route 10.231.0.0 255.255.255.0 @@ -70,8 +70,8 @@ route 10.231.0.0 255.255.255.0 And also you can generate client configurations: -```bash -# vault-openvpn --auto-revoke --pki-mountpoint luzifer_io client workwork01.openvpn.luzifer.io +```console +$ vault-openvpn --auto-revoke --pki-mountpoint luzifer_io client workwork01.openvpn.luzifer.io remote myserver.com 1194 udp [...] @@ -79,8 +79,8 @@ remote myserver.com 1194 udp In case someone needs to get removed from your OpenVPN there is also a revoke: -```bash -# vault-openvpn --auto-revoke --pki-mountpoint luzifer_io revoke baduser.openvpn.luzifer.io +```console +$ vault-openvpn --auto-revoke --pki-mountpoint luzifer_io revoke baduser.openvpn.luzifer.io [...] 2016/07/25 15:06:58 Found certificate 33:e1:0c:85:36:a5:c2:6b:05:85:f5:aa:9f:3b:f3:3a:a2:e0:ae:b0 with CN baduser.openvpn.luzifer.io 2016/07/25 15:06:58 Revoked certificate 33:e1:0c:85:36:a5:c2:6b:05:85:f5:aa:9f:3b:f3:3a:a2:e0:ae:b0 @@ -89,31 +89,31 @@ In case someone needs to get removed from your OpenVPN there is also a revoke: To have revokes being executed by OpenVPN you need to periodically update the CRL file OpenVPN reads. For my solution see the `living-example` in the `example` folder. -## Using Tls Auth -OpenVPN highly recommends using TLS Authentication hardening, see https://community.openvpn.net/openvpn/wiki/GettingStartedwithOVPN#TLSAuthentication +## Using TLS authentication +OpenVPN highly recommends using TLS authentication hardening, see [GettingStartedwithOVPN](https://community.openvpn.net/openvpn/wiki/GettingStartedwithOVPN#TLSAuthentication). -This requires the use of a pre-shared key, if you want to use it you will first need to generate tls auth key and then upload it to vault. +This requires the use of a pre-shared key: If you want to use it, you will first need to generate a TLS authentication key and then upload it into vault: -```bash -openvpn --genkey --secret openvpn.key -vault kv put secret/ovpn key=@openvpn.key +```console +$ openvpn --genkey --secret openvpn.key +$ vault kv put secret/ovpn key=@openvpn.key ``` -In the above example we call the secret "ovpn" but you can call it anything you want, so long as its a known value. -The key must be placed into both the client and server configurations and must match, edit both config templates to include a section as shown below +In the above example we call the secret "ovpn" but you can call it anything you want, as long as it is a known value. +The key must be placed into both the client and server configurations and must match. Edit both config templates to include a section as shown below: ``` -{{ .TlsAuth }} +{{ .TLSAuth }} ``` Now run vault-openvpn passing in the name of the secret that holds our key, e.g. -```bash +```console # for the server config -vault-openvpn --auto-revoke --ovpn-key ovpn --pki-mountpoint luzifer_io server edda.openvpn.luzifer.io +$ vault-openvpn --auto-revoke --ovpn-key secret/ovpn --pki-mountpoint luzifer_io server edda.openvpn.luzifer.io -# and for the client config -vault-openvpn --auto-revoke --ovpn-key ovpn --pki-mountpoint luzifer_io client workwork01.openvpn.luzifer.io +# for the client config +$ vault-openvpn --auto-revoke --ovpn-key secret/ovpn --pki-mountpoint luzifer_io client workwork01.openvpn.luzifer.io ``` From 470ecccfecacb25adaac6f4f195a14dfb27a0ae4 Mon Sep 17 00:00:00 2001 From: Knut Ahlers Date: Sun, 27 May 2018 10:30:28 +0200 Subject: [PATCH 3/3] Include feedback from #7 Signed-off-by: Knut Ahlers --- main.go | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/main.go b/main.go index 82d6097..5cb8a2b 100644 --- a/main.go +++ b/main.go @@ -45,7 +45,7 @@ var ( AutoRevoke bool `flag:"auto-revoke" vardefault:"auto-revoke" description:"Automatically revoke older certificates for this FQDN"` CertTTL time.Duration `flag:"ttl" vardefault:"ttl" description:"Set the TTL for this certificate"` - OvpnKey string `flag:"ovpn-key" vardefault:"secret/ovpn" description:"Specify a secret name that holds an OpenVPN shared key"` + OVPNKey string `flag:"ovpn-key" vardefault:"ovpn-key" description:"Specify a secret name that holds an OpenVPN shared key"` LogLevel string `flag:"log-level" vardefault:"log-level" description:"Log level to use (debug, info, warning, error)"` Sort string `flag:"sort" vardefault:"sort" description:"How to sort list output (fqdn, issuedate, expiredate)"` @@ -54,13 +54,14 @@ var ( }{} defaultConfig = map[string]string{ + "auto-revoke": "true", + "log-level": "info", + "ovpn-key": "", "pki-mountpoint": "/pki", "pki-role": "openvpn", - "auto-revoke": "true", - "ttl": "8760h", - "log-level": "info", "sort": "fqdn", "template-path": ".", + "ttl": "8760h", } version = "dev" @@ -72,7 +73,7 @@ type templateVars struct { CertAuthority string Certificate string PrivateKey string - TlsAuth string + TLSAuth string } type listCertificatesTableRow struct { @@ -292,10 +293,10 @@ func generateCertificateConfig(tplName, fqdn string) error { tplv.CertAuthority = caCert - if cfg.OvpnKey != "" { - tplv.TlsAuth, err = fetchOvpnKey(fqdn) + if cfg.OVPNKey != "" { + tplv.TLSAuth, err = fetchOVPNKey() if err != nil { - return fmt.Errorf("Could not fetch TlsAuth key: %s", err) + return fmt.Errorf("Could not fetch TLSAuth key: %s", err) } } @@ -443,18 +444,24 @@ func getCACert() (string, error) { return cs.Data["certificate"].(string), nil } -func fetchOvpnKey(fqdn string) (string, error) { - path := strings.Join([]string{"secret", "data", strings.Trim(cfg.OvpnKey, "/")}, "/") +func fetchOVPNKey() (string, error) { + path := strings.Trim(cfg.OVPNKey, "/") secret, err := client.Logical().Read(path) if err != nil { return "", err } - if secret == nil { + if secret == nil || secret.Data == nil { return "", errors.New("Got no data from backend") } - return secret.Data["data"].(map[string]interface {})["key"].(string), nil + + key, ok := secret.Data["key"] + if !ok { + return "", errors.New("Within specified secret no entry named 'key' was found") + } + + return key.(string), nil } func generateCertificate(fqdn string) (*templateVars, error) {