Feature: Docker secrets, refers to #306
This commit is contained in:
@@ -3,8 +3,6 @@ package params
|
||||
import (
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
@@ -25,23 +23,15 @@ func (p *reader) GetCyberghostRegions() (regions []string, err error) {
|
||||
return p.envParams.GetCSVInPossibilities("REGION", constants.CyberghostRegionChoices())
|
||||
}
|
||||
|
||||
// GetCyberghostClientKey obtains the one line client key to use for openvpn from the
|
||||
// file at /gluetun/client.key.
|
||||
// GetCyberghostClientKey obtains the client key to use for openvpn
|
||||
// from the secret file /run/secrets/openvpn_clientkey or from the file
|
||||
// /gluetun/client.key.
|
||||
func (p *reader) GetCyberghostClientKey() (clientKey string, err error) {
|
||||
const filepath = string(constants.ClientKey)
|
||||
file, err := p.os.OpenFile(filepath, os.O_RDONLY, 0)
|
||||
b, err := p.getFromFileOrSecretFile("OPENVPN_CLIENTKEY", string(constants.ClientKey))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
content, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
_ = file.Close()
|
||||
return "", err
|
||||
}
|
||||
if err := file.Close(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return extractClientKey(content)
|
||||
return extractClientKey(b)
|
||||
}
|
||||
|
||||
func extractClientKey(b []byte) (key string, err error) {
|
||||
@@ -57,23 +47,15 @@ func extractClientKey(b []byte) (key string, err error) {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// GetCyberghostClientCertificate obtains the client certificate to use for openvpn from the
|
||||
// file at /gluetun/client.crt.
|
||||
// GetCyberghostClientCertificate obtains the client certificate to use for openvpn
|
||||
// from the secret file /run/secrets/openvpn_clientcrt or from the file
|
||||
// /gluetun/client.crt.
|
||||
func (p *reader) GetCyberghostClientCertificate() (clientCertificate string, err error) {
|
||||
const filepath = string(constants.ClientCertificate)
|
||||
file, err := p.os.OpenFile(filepath, os.O_RDONLY, 0)
|
||||
b, err := p.getFromFileOrSecretFile("OPENVPN_CLIENTCRT", string(constants.ClientCertificate))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
content, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
_ = file.Close()
|
||||
return "", err
|
||||
}
|
||||
if err := file.Close(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return extractClientCertificate(content)
|
||||
return extractClientCertificate(b)
|
||||
}
|
||||
|
||||
func extractClientCertificate(b []byte) (certificate string, err error) {
|
||||
|
||||
@@ -49,26 +49,28 @@ func (r *reader) GetHTTPProxyPort() (port uint16, err error) {
|
||||
return r.envParams.GetPort("HTTPPROXY_PORT", retroKeysOption, libparams.Default("8888"))
|
||||
}
|
||||
|
||||
// GetHTTPProxyUser obtains the HTTP proxy server user from the environment variable
|
||||
// HTTPPROXY_USER, and using TINYPROXY_USER and PROXY_USER as retro-compatibility names.
|
||||
// GetHTTPProxyUser obtains the HTTP proxy server user.
|
||||
// It first tries to use the HTTPPROXY_USER environment variable (easier for the end user)
|
||||
// and then tries to read from the secret file httpproxy_user if nothing was found.
|
||||
func (r *reader) GetHTTPProxyUser() (user string, err error) {
|
||||
retroKeysOption := libparams.RetroKeys(
|
||||
const compulsory = false
|
||||
return r.getFromEnvOrSecretFile(
|
||||
"HTTPPROXY_USER",
|
||||
compulsory,
|
||||
[]string{"TINYPROXY_USER", "PROXY_USER"},
|
||||
r.onRetroActive,
|
||||
)
|
||||
return r.envParams.GetEnv("HTTPPROXY_USER",
|
||||
retroKeysOption, libparams.CaseSensitiveValue(), libparams.Unset())
|
||||
}
|
||||
|
||||
// GetHTTPProxyPassword obtains the HTTP proxy server password from the environment variable
|
||||
// HTTPPROXY_PASSWORD, and using TINYPROXY_PASSWORD and PROXY_PASSWORD as retro-compatibility names.
|
||||
// GetHTTPProxyPassword obtains the HTTP proxy server password.
|
||||
// It first tries to use the HTTPPROXY_PASSWORD environment variable (easier for the end user)
|
||||
// and then tries to read from the secret file httpproxy_password if nothing was found.
|
||||
func (r *reader) GetHTTPProxyPassword() (password string, err error) {
|
||||
retroKeysOption := libparams.RetroKeys(
|
||||
const compulsory = false
|
||||
return r.getFromEnvOrSecretFile(
|
||||
"HTTPPROXY_USER",
|
||||
compulsory,
|
||||
[]string{"TINYPROXY_PASSWORD", "PROXY_PASSWORD"},
|
||||
r.onRetroActive,
|
||||
)
|
||||
return r.envParams.GetEnv("HTTPPROXY_PASSWORD",
|
||||
retroKeysOption, libparams.CaseSensitiveValue(), libparams.Unset())
|
||||
}
|
||||
|
||||
// GetHTTPProxyStealth obtains the HTTP proxy server stealth mode
|
||||
|
||||
@@ -9,23 +9,19 @@ import (
|
||||
)
|
||||
|
||||
// GetUser obtains the user to use to connect to the VPN servers.
|
||||
// It first tries to use the OPENVPN_USER environment variable (easier for the end user)
|
||||
// and then tries to read from the secret file openvpn_user if nothing was found.
|
||||
func (r *reader) GetUser() (user string, err error) {
|
||||
return r.envParams.GetEnv("OPENVPN_USER",
|
||||
libparams.CaseSensitiveValue(),
|
||||
libparams.Compulsory(),
|
||||
libparams.RetroKeys([]string{"USER"}, r.onRetroActive),
|
||||
libparams.Unset())
|
||||
const compulsory = true
|
||||
return r.getFromEnvOrSecretFile("OPENVPN_USER", compulsory, []string{"USER"})
|
||||
}
|
||||
|
||||
// GetPassword obtains the password to use to connect to the VPN servers.
|
||||
// It first tries to use the OPENVPN_PASSWORD environment variable (easier for the end user)
|
||||
// and then tries to read from the secret file openvpn_password if nothing was found.
|
||||
func (r *reader) GetPassword() (s string, err error) {
|
||||
options := []libparams.GetEnvSetter{
|
||||
libparams.CaseSensitiveValue(),
|
||||
libparams.Unset(),
|
||||
libparams.Compulsory(),
|
||||
libparams.RetroKeys([]string{"PASSWORD"}, r.onRetroActive),
|
||||
}
|
||||
return r.envParams.GetEnv("OPENVPN_PASSWORD", options...)
|
||||
const compulsory = true
|
||||
return r.getFromEnvOrSecretFile("OPENVPN_PASSWORD", compulsory, []string{"PASSWORD"})
|
||||
}
|
||||
|
||||
// GetNetworkProtocol obtains the network protocol to use to connect to the
|
||||
|
||||
108
internal/params/secrets.go
Normal file
108
internal/params/secrets.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package params
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/os"
|
||||
libparams "github.com/qdm12/golibs/params"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrGetSecretFilepath = errors.New("cannot get secret file path from env")
|
||||
ErrReadSecretFile = errors.New("cannot read secret file")
|
||||
ErrSecretFileIsEmpty = errors.New("secret file is empty")
|
||||
ErrReadNonSecretFile = errors.New("cannot read non secret file")
|
||||
ErrFilesDoNotExist = errors.New("files do not exist")
|
||||
)
|
||||
|
||||
func (r *reader) getFromEnvOrSecretFile(envKey string, compulsory bool, retroKeys []string) (value string, err error) {
|
||||
envOptions := []libparams.GetEnvSetter{
|
||||
libparams.Compulsory(), // to fallback on file reading
|
||||
libparams.CaseSensitiveValue(),
|
||||
libparams.Unset(),
|
||||
libparams.RetroKeys(retroKeys, r.onRetroActive),
|
||||
}
|
||||
value, envErr := r.envParams.GetEnv(envKey, envOptions...)
|
||||
if envErr == nil {
|
||||
return value, nil
|
||||
}
|
||||
|
||||
defaultSecretFile := "/run/secrets/" + strings.ToLower(envKey)
|
||||
filepath, err := r.envParams.GetEnv(envKey+"_SECRETFILE",
|
||||
libparams.CaseSensitiveValue(),
|
||||
libparams.Default(defaultSecretFile),
|
||||
)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w: %s", ErrGetSecretFilepath, err)
|
||||
}
|
||||
|
||||
file, fileErr := r.os.OpenFile(filepath, os.O_RDONLY, 0)
|
||||
if os.IsNotExist(fileErr) {
|
||||
if compulsory {
|
||||
return "", envErr
|
||||
}
|
||||
return "", nil
|
||||
} else if fileErr != nil {
|
||||
return "", fmt.Errorf("%w: %s", ErrReadSecretFile, fileErr)
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w: %s", ErrReadSecretFile, err)
|
||||
}
|
||||
|
||||
value = string(b)
|
||||
if compulsory && len(value) == 0 {
|
||||
return "", ErrSecretFileIsEmpty
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// Tries to read from the secret file then the non secret file.
|
||||
func (r *reader) getFromFileOrSecretFile(secretName, filepath string) (
|
||||
b []byte, err error) {
|
||||
defaultSecretFile := "/run/secrets/" + strings.ToLower(secretName)
|
||||
secretFilepath, err := r.envParams.GetEnv(strings.ToUpper(secretName)+"_SECRETFILE",
|
||||
libparams.CaseSensitiveValue(),
|
||||
libparams.Default(defaultSecretFile),
|
||||
)
|
||||
if err != nil {
|
||||
return b, fmt.Errorf("%w: %s", ErrGetSecretFilepath, err)
|
||||
}
|
||||
|
||||
b, err = readFromFile(r.os.OpenFile, secretFilepath)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return b, fmt.Errorf("%w: %s", ErrReadSecretFile, err)
|
||||
} else if err == nil {
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Secret file does not exist, try the non secret file
|
||||
b, err = readFromFile(r.os.OpenFile, filepath)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf("%w: %s", ErrReadSecretFile, err)
|
||||
} else if err == nil {
|
||||
return b, nil
|
||||
}
|
||||
return nil, fmt.Errorf("%w: %s and %s", ErrFilesDoNotExist, secretFilepath, filepath)
|
||||
}
|
||||
|
||||
func readFromFile(openFile os.OpenFileFunc, filepath string) (b []byte, err error) {
|
||||
file, err := openFile(filepath, os.O_RDONLY, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b, err = ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
_ = file.Close()
|
||||
return nil, err
|
||||
}
|
||||
if err := file.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
@@ -32,10 +32,12 @@ func (r *reader) GetShadowSocksPort() (port uint16, err error) {
|
||||
return uint16(portUint64), err
|
||||
}
|
||||
|
||||
// GetShadowSocksPassword obtains the ShadowSocks server password from the environment variable
|
||||
// SHADOWSOCKS_PASSWORD.
|
||||
// GetShadowSocksPassword obtains the ShadowSocks server password.
|
||||
// It first tries to use the SHADOWSOCKS_PASSWORD environment variable (easier for the end user)
|
||||
// and then tries to read from the secret file shadowsocks_password if nothing was found.
|
||||
func (r *reader) GetShadowSocksPassword() (password string, err error) {
|
||||
return r.envParams.GetEnv("SHADOWSOCKS_PASSWORD", libparams.CaseSensitiveValue(), libparams.Unset())
|
||||
const compulsory = false
|
||||
return r.getFromEnvOrSecretFile("SHADOWSOCKS_PASSWORD", compulsory, nil)
|
||||
}
|
||||
|
||||
// GetShadowSocksMethod obtains the ShadowSocks method to use from the environment variable
|
||||
|
||||
Reference in New Issue
Block a user