mirror of
https://github.com/Luzifer/vault-openvpn.git
synced 2024-12-25 14:21:21 +00:00
Merge branch 'tls-auth'
This commit is contained in:
commit
6048719362
2 changed files with 68 additions and 9 deletions
41
README.md
41
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:
|
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
|
```console
|
||||||
# vault-openvpn --auto-revoke --pki-mountpoint luzifer_io server edda.openvpn.luzifer.io
|
$ vault-openvpn --auto-revoke --pki-mountpoint luzifer_io server edda.openvpn.luzifer.io
|
||||||
server 10.231.0.0 255.255.255.0
|
server 10.231.0.0 255.255.255.0
|
||||||
route 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:
|
And also you can generate client configurations:
|
||||||
|
|
||||||
```bash
|
```console
|
||||||
# vault-openvpn --auto-revoke --pki-mountpoint luzifer_io client workwork01.openvpn.luzifer.io
|
$ vault-openvpn --auto-revoke --pki-mountpoint luzifer_io client workwork01.openvpn.luzifer.io
|
||||||
remote myserver.com 1194 udp
|
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:
|
In case someone needs to get removed from your OpenVPN there is also a revoke:
|
||||||
|
|
||||||
```bash
|
```console
|
||||||
# vault-openvpn --auto-revoke --pki-mountpoint luzifer_io revoke baduser.openvpn.luzifer.io
|
$ 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 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
|
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
|
||||||
|
@ -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.
|
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 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 a TLS authentication key and then upload it into vault:
|
||||||
|
|
||||||
|
```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, 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:
|
||||||
|
|
||||||
|
```
|
||||||
|
<tls-auth>
|
||||||
|
{{ .TLSAuth }}
|
||||||
|
</tls-auth>
|
||||||
|
```
|
||||||
|
|
||||||
|
Now run vault-openvpn passing in the name of the secret that holds our key, e.g.
|
||||||
|
|
||||||
|
```console
|
||||||
|
# for the server config
|
||||||
|
$ vault-openvpn --auto-revoke --ovpn-key secret/ovpn --pki-mountpoint luzifer_io server edda.openvpn.luzifer.io
|
||||||
|
|
||||||
|
# for the client config
|
||||||
|
$ vault-openvpn --auto-revoke --ovpn-key secret/ovpn --pki-mountpoint luzifer_io client workwork01.openvpn.luzifer.io
|
||||||
|
```
|
||||||
|
|
36
main.go
36
main.go
|
@ -45,6 +45,7 @@ var (
|
||||||
|
|
||||||
AutoRevoke bool `flag:"auto-revoke" vardefault:"auto-revoke" description:"Automatically revoke older certificates for this FQDN"`
|
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"`
|
CertTTL time.Duration `flag:"ttl" vardefault:"ttl" description:"Set the TTL for this certificate"`
|
||||||
|
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)"`
|
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)"`
|
Sort string `flag:"sort" vardefault:"sort" description:"How to sort list output (fqdn, issuedate, expiredate)"`
|
||||||
|
@ -53,13 +54,14 @@ var (
|
||||||
}{}
|
}{}
|
||||||
|
|
||||||
defaultConfig = map[string]string{
|
defaultConfig = map[string]string{
|
||||||
|
"auto-revoke": "true",
|
||||||
|
"log-level": "info",
|
||||||
|
"ovpn-key": "",
|
||||||
"pki-mountpoint": "/pki",
|
"pki-mountpoint": "/pki",
|
||||||
"pki-role": "openvpn",
|
"pki-role": "openvpn",
|
||||||
"auto-revoke": "true",
|
|
||||||
"ttl": "8760h",
|
|
||||||
"log-level": "info",
|
|
||||||
"sort": "fqdn",
|
"sort": "fqdn",
|
||||||
"template-path": ".",
|
"template-path": ".",
|
||||||
|
"ttl": "8760h",
|
||||||
}
|
}
|
||||||
|
|
||||||
version = "dev"
|
version = "dev"
|
||||||
|
@ -71,6 +73,7 @@ type templateVars struct {
|
||||||
CertAuthority string
|
CertAuthority string
|
||||||
Certificate string
|
Certificate string
|
||||||
PrivateKey string
|
PrivateKey string
|
||||||
|
TLSAuth string
|
||||||
}
|
}
|
||||||
|
|
||||||
type listCertificatesTableRow struct {
|
type listCertificatesTableRow struct {
|
||||||
|
@ -290,6 +293,13 @@ func generateCertificateConfig(tplName, fqdn string) error {
|
||||||
|
|
||||||
tplv.CertAuthority = caCert
|
tplv.CertAuthority = caCert
|
||||||
|
|
||||||
|
if cfg.OVPNKey != "" {
|
||||||
|
tplv.TLSAuth, err = fetchOVPNKey()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Could not fetch TLSAuth key: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := renderTemplate(tplName, tplv); err != nil {
|
if err := renderTemplate(tplName, tplv); err != nil {
|
||||||
return fmt.Errorf("Could not render configuration: %s", err)
|
return fmt.Errorf("Could not render configuration: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -434,6 +444,26 @@ func getCACert() (string, error) {
|
||||||
return cs.Data["certificate"].(string), nil
|
return cs.Data["certificate"].(string), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fetchOVPNKey() (string, error) {
|
||||||
|
path := strings.Trim(cfg.OVPNKey, "/")
|
||||||
|
secret, err := client.Logical().Read(path)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if secret == nil || secret.Data == nil {
|
||||||
|
return "", errors.New("Got no data from backend")
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
func generateCertificate(fqdn string) (*templateVars, error) {
|
||||||
path := strings.Join([]string{strings.Trim(cfg.PKIMountPoint, "/"), "issue", cfg.PKIRole}, "/")
|
path := strings.Join([]string{strings.Trim(cfg.PKIMountPoint, "/"), "issue", cfg.PKIRole}, "/")
|
||||||
secret, err := client.Logical().Write(path, map[string]interface{}{
|
secret, err := client.Logical().Write(path, map[string]interface{}{
|
||||||
|
|
Loading…
Reference in a new issue