fix(settings): read PEM files but b64 env vars

- Extract base64 data from PEM files and secret files
- Environment variables are not PEM encoded and only the base64 data
- Affects OpenVPN certificate, key and encrypted key
This commit is contained in:
Quentin McGaw
2022-08-24 17:48:45 +00:00
parent 647cd07de7
commit 062b6a276c
8 changed files with 59 additions and 67 deletions

View File

@@ -1,6 +1,7 @@
package settings package settings
import ( import (
"encoding/base64"
"fmt" "fmt"
"regexp" "regexp"
"strings" "strings"
@@ -193,7 +194,7 @@ func validateOpenVPNClientCertificate(vpnProvider,
return nil return nil
} }
_, err = extract.PEM([]byte(clientCert)) _, err = base64.StdEncoding.DecodeString(clientCert)
if err != nil { if err != nil {
return err return err
} }
@@ -215,7 +216,7 @@ func validateOpenVPNClientKey(vpnProvider, clientKey string) (err error) {
return nil return nil
} }
_, err = extract.PEM([]byte(clientKey)) _, err = base64.StdEncoding.DecodeString(clientKey)
if err != nil { if err != nil {
return err return err
} }
@@ -232,9 +233,9 @@ func validateOpenVPNEncryptedKey(vpnProvider,
return nil return nil
} }
_, err = extract.PEM([]byte(encryptedPrivateKey)) _, err = base64.StdEncoding.DecodeString(encryptedPrivateKey)
if err != nil { if err != nil {
return fmt.Errorf("extracting encrypted key: %w", err) return err
} }
return nil return nil
} }

View File

@@ -1,7 +1,6 @@
package env package env
import ( import (
"encoding/base64"
"fmt" "fmt"
"os" "os"
"strconv" "strconv"
@@ -133,15 +132,6 @@ func lowerAndSplit(csv string) (values []string) {
return strings.Split(csv, ",") return strings.Split(csv, ",")
} }
func decodeBase64(b64String string) (decoded string, err error) {
b, err := base64.StdEncoding.DecodeString(b64String)
if err != nil {
return "", fmt.Errorf("cannot decode base64 string %q: %w",
b64String, err)
}
return string(b), nil
}
func unsetEnvKeys(envKeys []string, err error) (newErr error) { func unsetEnvKeys(envKeys []string, err error) (newErr error) {
newErr = err newErr = err
for _, envKey := range envKeys { for _, envKey := range envKeys {

View File

@@ -31,20 +31,9 @@ func (r *Reader) readOpenVPN() (
openVPN.Auth = &auth openVPN.Auth = &auth
} }
openVPN.Cert, err = readBase64OrNil("OPENVPN_CERT") openVPN.Cert = envToStringPtr("OPENVPN_CERT")
if err != nil { openVPN.Key = envToStringPtr("OPENVPN_KEY")
return openVPN, fmt.Errorf("environment variable OPENVPN_CERT: %w", err) openVPN.EncryptedKey = envToStringPtr("OPENVPN_ENCRYPTED_KEY")
}
openVPN.Key, err = readBase64OrNil("OPENVPN_KEY")
if err != nil {
return openVPN, fmt.Errorf("environment variable OPENVPN_KEY: %w", err)
}
openVPN.EncryptedKey, err = readBase64OrNil("OPENVPN_ENCRYPTED_KEY")
if err != nil {
return openVPN, fmt.Errorf("environment variable OPENVPN_ENCRYPTED_KEY: %w", err)
}
openVPN.KeyPassphrase = r.readOpenVPNKeyPassphrase() openVPN.KeyPassphrase = r.readOpenVPNKeyPassphrase()
@@ -111,20 +100,6 @@ func (r *Reader) readOpenVPNKeyPassphrase() (passphrase *string) {
return passphrase return passphrase
} }
func readBase64OrNil(envKey string) (valueOrNil *string, err error) {
value := getCleanedEnv(envKey)
if value == "" {
return nil, nil //nolint:nilnil
}
decoded, err := decodeBase64(value)
if err != nil {
return nil, err
}
return &decoded, nil
}
func (r *Reader) readPIAEncryptionPreset() (presetPtr *string) { func (r *Reader) readPIAEncryptionPreset() (presetPtr *string) {
_, preset := r.getEnvWithRetro( _, preset := r.getEnvWithRetro(
"PRIVATE_INTERNET_ACCESS_OPENVPN_ENCRYPTION_PRESET", "PRIVATE_INTERNET_ACCESS_OPENVPN_ENCRYPTION_PRESET",

View File

@@ -1,9 +1,12 @@
package files package files
import ( import (
"fmt"
"io" "io"
"os" "os"
"strings" "strings"
"github.com/qdm12/gluetun/internal/openvpn/extract"
) )
// ReadFromFile reads the content of the file as a string. // ReadFromFile reads the content of the file as a string.
@@ -32,3 +35,21 @@ func ReadFromFile(filepath string) (s *string, err error) {
content = strings.TrimSuffix(content, "\n") content = strings.TrimSuffix(content, "\n")
return &content, nil return &content, nil
} }
func readPEMFile(filepath string) (base64Ptr *string, err error) {
pemData, err := ReadFromFile(filepath)
if err != nil {
return nil, fmt.Errorf("reading file: %w", err)
}
if pemData == nil {
return nil, nil //nolint:nilnil
}
base64Data, err := extract.PEM([]byte(*pemData))
if err != nil {
return nil, fmt.Errorf("extracting base64 encoded data from PEM content: %w", err)
}
return &base64Data, nil
}

View File

@@ -15,17 +15,16 @@ const (
) )
func (r *Reader) readOpenVPN() (settings settings.OpenVPN, err error) { func (r *Reader) readOpenVPN() (settings settings.OpenVPN, err error) {
settings.Key, err = ReadFromFile(OpenVPNClientKeyPath) settings.Key, err = readPEMFile(OpenVPNClientKeyPath)
if err != nil { if err != nil {
return settings, fmt.Errorf("client key: %w", err) return settings, fmt.Errorf("client key: %w", err)
} }
settings.Cert, err = ReadFromFile(OpenVPNClientCertificatePath) settings.Cert, err = readPEMFile(OpenVPNClientCertificatePath)
if err != nil { if err != nil {
return settings, fmt.Errorf("client certificate: %w", err) return settings, fmt.Errorf("client certificate: %w", err)
} }
settings.EncryptedKey, err = readPEMFile(openVPNEncryptedKey)
settings.EncryptedKey, err = ReadFromFile(openVPNEncryptedKey)
if err != nil { if err != nil {
return settings, fmt.Errorf("reading encrypted key file: %w", err) return settings, fmt.Errorf("reading encrypted key file: %w", err)
} }

View File

@@ -1,10 +1,12 @@
package secrets package secrets
import ( import (
"fmt"
"os" "os"
"strings" "strings"
"github.com/qdm12/gluetun/internal/configuration/sources/files" "github.com/qdm12/gluetun/internal/configuration/sources/files"
"github.com/qdm12/gluetun/internal/openvpn/extract"
) )
// getCleanedEnv returns an environment variable value with // getCleanedEnv returns an environment variable value with
@@ -25,3 +27,22 @@ func readSecretFileAsStringPtr(secretPathEnvKey, defaultSecretPath string) (
} }
return files.ReadFromFile(path) return files.ReadFromFile(path)
} }
func readPEMSecretFile(secretPathEnvKey, defaultSecretPath string) (
base64Ptr *string, err error) {
pemData, err := readSecretFileAsStringPtr(secretPathEnvKey, defaultSecretPath)
if err != nil {
return nil, fmt.Errorf("reading secret file: %w", err)
}
if pemData == nil {
return nil, nil //nolint:nilnil
}
base64Data, err := extract.PEM([]byte(*pemData))
if err != nil {
return nil, fmt.Errorf("extracting base64 encoded data from PEM content: %w", err)
}
return &base64Data, nil
}

View File

@@ -24,7 +24,7 @@ func readOpenVPN() (
return settings, fmt.Errorf("cannot read password file: %w", err) return settings, fmt.Errorf("cannot read password file: %w", err)
} }
settings.Key, err = readSecretFileAsStringPtr( settings.Key, err = readPEMSecretFile(
"OPENVPN_CLIENTKEY_SECRETFILE", "OPENVPN_CLIENTKEY_SECRETFILE",
"/run/secrets/openvpn_clientkey", "/run/secrets/openvpn_clientkey",
) )
@@ -32,7 +32,7 @@ func readOpenVPN() (
return settings, fmt.Errorf("cannot read client key file: %w", err) return settings, fmt.Errorf("cannot read client key file: %w", err)
} }
settings.EncryptedKey, err = readSecretFileAsStringPtr( settings.EncryptedKey, err = readPEMSecretFile(
"OPENVPN_ENCRYPTED_KEY_SECRETFILE", "OPENVPN_ENCRYPTED_KEY_SECRETFILE",
"/run/secrets/openvpn_encrypted_key", "/run/secrets/openvpn_encrypted_key",
) )
@@ -48,7 +48,7 @@ func readOpenVPN() (
return settings, fmt.Errorf("reading key passphrase file: %w", err) return settings, fmt.Errorf("reading key passphrase file: %w", err)
} }
settings.Cert, err = readSecretFileAsStringPtr( settings.Cert, err = readPEMSecretFile(
"OPENVPN_CLIENTCRT_SECRETFILE", "OPENVPN_CLIENTCRT_SECRETFILE",
"/run/secrets/openvpn_clientcrt", "/run/secrets/openvpn_clientcrt",
) )

View File

@@ -8,7 +8,6 @@ import (
"github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/constants/openvpn" "github.com/qdm12/gluetun/internal/constants/openvpn"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/openvpn/extract"
) )
type OpenVPNProviderSettings struct { type OpenVPNProviderSettings struct {
@@ -191,21 +190,15 @@ func OpenVPNConfig(provider OpenVPNProviderSettings,
if *settings.EncryptedKey != "" { if *settings.EncryptedKey != "" {
lines.add("askpass", openvpn.AskPassPath) lines.add("askpass", openvpn.AskPassPath)
keyData, err := extract.PEM([]byte(*settings.EncryptedKey)) lines.addLines(WrapOpenvpnEncryptedKey(*settings.EncryptedKey))
panicOnError(err, "cannot extract PEM encrypted key")
lines.addLines(WrapOpenvpnEncryptedKey(keyData))
} }
if *settings.Cert != "" { if *settings.Cert != "" {
certData, err := extract.PEM([]byte(*settings.Cert)) lines.addLines(WrapOpenvpnCert(*settings.Cert))
panicOnError(err, "cannot extract OpenVPN certificate")
lines.addLines(WrapOpenvpnCert(certData))
} }
if *settings.Key != "" { if *settings.Key != "" {
keyData, err := extract.PEM([]byte(*settings.Key)) lines.addLines(WrapOpenvpnKey(*settings.Key))
panicOnError(err, "cannot extract OpenVPN key")
lines.addLines(WrapOpenvpnKey(keyData))
} }
lines.addLines(provider.ExtraLines) lines.addLines(provider.ExtraLines)
@@ -254,14 +247,6 @@ func defaultStringSlice(value, defaultValue []string) (
return result return result
} }
func panicOnError(err error, context string) {
if err == nil {
return
}
panicMessage := fmt.Sprintf("%s: %s", context, err)
panic(panicMessage)
}
func WrapOpenvpnCA(certificate string) (lines []string) { func WrapOpenvpnCA(certificate string) (lines []string) {
return []string{ return []string{
"<ca>", "<ca>",