Skip to content

Commit

Permalink
lnconfig: Support utilizing Environment Variables in lnd.conf for `…
Browse files Browse the repository at this point in the history
…rpcuser` and `rpcpass` fields.

- Added `supplyEnvValue` function in `config.go` that returns The value of the specified environment variable, or the default value if provided, or the original input string if no matching variable is found or set.
- Called `supplyEnvValue` function in `parseRPCParams` function in `config.go` file where `rpcuser` and `rpcpass` fields are being parsed.
- Added the release notes in the docs.
  • Loading branch information
mohamedawnallah committed Jan 5, 2024
1 parent 0df507e commit 6f8b242
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 2 deletions.
75 changes: 73 additions & 2 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -1777,6 +1777,11 @@ func parseRPCParams(cConfig *lncfg.Chain, nodeConfig interface{},
var daemonName, confDir, confFile, confFileBase string
switch conf := nodeConfig.(type) {
case *lncfg.Btcd:
// Resolves environment variable references in RPCUser and
// RPCPass fields.
conf.RPCUser = supplyEnvValue(conf.RPCUser)
conf.RPCPass = supplyEnvValue(conf.RPCPass)

// If both RPCUser and RPCPass are set, we assume those
// credentials are good to use.
if conf.RPCUser != "" && conf.RPCPass != "" {
Expand Down Expand Up @@ -1822,6 +1827,11 @@ func parseRPCParams(cConfig *lncfg.Chain, nodeConfig interface{},
confFile = conf.ConfigPath
confFileBase = BitcoinChainName

// Resolves environment variable references in RPCUser
// and RPCPass fields.
conf.RPCUser = supplyEnvValue(conf.RPCUser)
conf.RPCPass = supplyEnvValue(conf.RPCPass)

// Check that cookie and credentials don't contradict each
// other.
if (conf.RPCUser != "" || conf.RPCPass != "") &&
Expand Down Expand Up @@ -1917,6 +1927,57 @@ func parseRPCParams(cConfig *lncfg.Chain, nodeConfig interface{},
return nil
}

// supplyEnvValue supplies the value of an environment variable from a string.
// It supports the following formats:
// 1) $ENVIRONMENT_VARIABLE
// 2) ${ENVIRONMENT_VARIABLE}
// 3) ${ENVIRONMENT_VARIABLE:-DEFAULT_VALUE}
//
// Standard environment variable naming conventions:
// - ENVIRONMENT_VARIABLE contains letters, digits, and underscores, and does
// not start with a digit.
// - DEFAULT_VALUE follows the rule that it can contain any characters except
// whitespace.
//
// Parameters:
// - value: The input string containing references to environment variables.
//
// Returns:
// - string: The value of the specified environment variable, or the default
// value if provided, or the original input string if no matching variable is
// found or set.
func supplyEnvValue(value string) string {
re := regexp.MustCompile(`^((\${([a-zA-Z_][a-zA-Z0-9_]*)?(:-(\S+))?})
|(\$([a-zA-Z_][a-zA-Z0-9_]*)))$`)

matches := re.FindStringSubmatch(value)
if len(matches) > 0 {
// ENVIRONMENT_VARIABLE, Group 3 corresponding to the following
// formats:
// ${ENVIRONMENT_VARIABLE}
// ${ENVIRONMENT_VARIABLE:-DEFAULT_VALUE}
envVariable := matches[3]
// ENVIRONMENT_VARIABLE, Group 7 corresponding to this format:
// $ENVIRONMENT_VARIABLE
if matches[7] != "" {
envVariable = matches[7]
}

envValue := os.Getenv(envVariable)

// Use the default value if the environment variable is not set
if envValue == "" {
// DEFAULT_VALUE, Group 5 corresponding to the format:
// ${ENVIRONMENT_VARIABLE:-DEFAULT_VALUE}
envValue = matches[5]
}

return envValue
}

return value
}

// extractBtcdRPCParams attempts to extract the RPC credentials for an existing
// btcd instance. The passed path is expected to be the location of btcd's
// application data directory on the target system.
Expand Down Expand Up @@ -1960,7 +2021,12 @@ func extractBtcdRPCParams(btcdConfigPath string) (string, string, error) {
return "", "", fmt.Errorf("unable to find rpcuser in config")
}

return string(userSubmatches[1]), string(passSubmatches[1]), nil
// Resolves environment variable references in RPCUser and RPCPass
// fields.
rpcUser := supplyEnvValue(string(userSubmatches[1]))
rpcPass := supplyEnvValue(string(passSubmatches[1]))

return rpcUser, rpcPass, nil
}

// extractBitcoindRPCParams attempts to extract the RPC credentials for an
Expand Down Expand Up @@ -2085,7 +2151,12 @@ func extractBitcoindRPCParams(networkName, bitcoindDataDir, bitcoindConfigPath,
"in config")
}

return string(userSubmatches[1]), string(passSubmatches[1]),
// Resolves environment variable references in RPCUser and RPCPass
// fields.
rpcUser := supplyEnvValue(string(userSubmatches[1]))
rpcPass := supplyEnvValue(string(passSubmatches[1]))

return rpcUser, rpcPass,
zmqBlockHost, zmqTxHost, nil
}

Expand Down
3 changes: 3 additions & 0 deletions docs/release-notes/release-notes-0.18.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@
the new payment status `Payment_INITIATED` should be used for payment-related
RPCs. It's recommended to use it to provide granular controls over payments.

* Support utilizing environment variables in `lnd.conf` to better protect the
secrets for `rpcuser` and `rpcpass` fields (https://github.com/lightningnetwork/lnd/pull/8310).

## RPC Additions

* [Deprecated](https://github.com/lightningnetwork/lnd/pull/7175)
Expand Down

0 comments on commit 6f8b242

Please sign in to comment.