This commit is contained in:
Vlom 2025-10-29 23:38:30 +01:00 committed by GitHub
commit 456f4f885f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 235 additions and 1 deletions

View file

@ -89,6 +89,79 @@ Memorising docker commands is hard. Memorising aliases is slightly less hard. Ke
- Docker >= **1.13** (API >= **1.25**)
- Docker-Compose >= **1.23.2** (optional)
## TLS Configuration
Lazydocker supports secure connections to Docker daemon using TLS. To enable TLS, you can configure it in your config.yml:
### Basic TLS Configuration
```yaml
tls:
enable: true
caCertPath: "/path/to/ca.pem"
certPath: "/path/to/cert.pem"
keyPath: "/path/to/key.pem"
```
### Complete TLS Configuration
```yaml
tls:
enable: true # Enable TLS connections to Docker daemon
caCertPath: "/path/to/ca.pem" # Path to Certificate Authority (CA) certificate
certPath: "/path/to/cert.pem" # Path to client certificate
keyPath: "/path/to/key.pem" # Path to client private key
host: "docker.example.com" # Hostname or IP for certificate validation (ServerName)
insecureSkipVerify: false # Skip TLS certificate verification (NOT recommended for production)
```
### TLS Configuration Options
- **`enable`**: Set to `true` to enable TLS connections to the Docker daemon
- **`caCertPath`**: Path to the Certificate Authority (CA) certificate file used to verify the Docker daemon's certificate
- **`certPath`**: Path to the client certificate file for mutual TLS authentication
- **`keyPath`**: Path to the client private key file corresponding to the client certificate
- **`host`**: The hostname or IP address expected on the Docker daemon's certificate. This must match the Common Name (CN) or a Subject Alternative Name (SAN) in the server's certificate
- **`insecureSkipVerify`**: When set to `true`, skips certificate verification (useful for testing, but insecure for production use)
### Important Notes
1. **Two Different "Hosts"**: Don't confuse the `tls.host` config field with the `DOCKER_HOST` environment variable:
- `DOCKER_HOST` environment variable: Tells Lazydocker **where to connect** (e.g., `tcp://192.168.1.100:2376`)
- `tls.host` in config.yml: Tells Lazydocker **what name to expect on the certificate** (e.g., `docker.example.com` or `192.168.1.100`)
2. **Certificate Validation**: The `host` field must match a name in your Docker daemon's certificate:
- Common Name (CN) in the certificate's Subject field
- Or one of the Subject Alternative Names (SANs) in the certificate
3. **Security**: Always use `insecureSkipVerify: false` in production environments. Only set it to `true` for testing purposes.
### Example for Remote Docker Daemon
When connecting to a Docker daemon running on a remote machine with TLS:
1. Set the connection endpoint:
```bash
export DOCKER_HOST=tcp://docker.example.com:2376
```
2. Configure TLS in `config.yml`:
```yaml
tls:
enable: true
caCertPath: "/home/user/.docker/ca.pem"
certPath: "/home/user/.docker/cert.pem"
keyPath: "/home/user/.docker/key.pem"
host: "docker.example.com" # Must match the name on the server's certificate
insecureSkipVerify: false
```
### Troubleshooting TLS Issues
- **"x509: certificate is valid for ..., not ..."**: The `host` field doesn't match any name on the server's certificate. Check your server certificate's CN and SANs.
- **"certificate signed by unknown authority"**: The CA certificate path is incorrect or the server's certificate wasn't signed by the specified CA.
- **"no such host"**: This is a network connectivity issue with `DOCKER_HOST`, not a TLS configuration problem.
## Installation
### Homebrew

View file

@ -64,6 +64,13 @@ logs:
timestamps: false
since: '60m' # set to '' to show all logs
tail: '' # set to 200 to show last 200 lines of logs
tls:
enable: false # Set to true to enable TLS connections to Docker daemon
caCertPath: "" # Path to Certificate Authority (CA) certificate file
certPath: "" # Path to client certificate file for mutual TLS authentication
keyPath: "" # Path to client private key file
host: "" # Hostname or IP for certificate validation (must match server certificate)
insecureSkipVerify: false # Skip certificate verification (NOT recommended for production)
commandTemplates:
dockerCompose: docker compose # Determines the Docker Compose command to run, referred to as .DockerCompose in commandTemplates
restartService: '{{ .DockerCompose }} restart {{ .Service.Name }}'
@ -97,6 +104,87 @@ stats:
## To see what all of the config options mean, and what other options you can set, see [here](https://godoc.org/github.com/jesseduffield/lazydocker/pkg/config)
## TLS Configuration
Lazydocker supports secure connections to Docker daemon using TLS (Transport Layer Security). This is essential when connecting to remote Docker daemons or when your Docker daemon requires client certificate authentication.
### Configuration Options
The `tls` section in your config supports the following options:
- **`enable`**: Boolean flag to enable/disable TLS connections
- **`caCertPath`**: Path to the Certificate Authority (CA) certificate file used to verify the Docker daemon's certificate
- **`certPath`**: Path to the client certificate file for mutual TLS authentication
- **`keyPath`**: Path to the client private key file corresponding to the client certificate
- **`host`**: The hostname or IP address expected on the Docker daemon's certificate. This must match the Common Name (CN) or a Subject Alternative Name (SAN) in the server's certificate
- **`insecureSkipVerify`**: When set to `true`, skips certificate verification. **Only use this for testing - it's insecure for production!**
### Basic Example
```yaml
tls:
enable: true
caCertPath: "/home/user/.docker/ca.pem"
certPath: "/home/user/.docker/cert.pem"
keyPath: "/home/user/.docker/key.pem"
host: "docker.example.com"
insecureSkipVerify: false
```
### Remote Docker Daemon Setup
When connecting to a remote Docker daemon with TLS:
1. **Set the Docker Host**: Use the `DOCKER_HOST` environment variable to specify where to connect:
```bash
export DOCKER_HOST=tcp://docker.example.com:2376
```
2. **Configure TLS**: Update your `config.yml`:
```yaml
tls:
enable: true
caCertPath: "/path/to/ca.pem"
certPath: "/path/to/cert.pem"
keyPath: "/path/to/key.pem"
host: "docker.example.com" # Must match certificate
insecureSkipVerify: false
```
### Important Notes
1. **Don't confuse two different "hosts"**:
- `DOCKER_HOST` environment variable: **WHERE** to connect (e.g., `tcp://192.168.1.100:2376`)
- `tls.host` config field: **WHAT NAME** to expect on the certificate (e.g., `docker.example.com`)
2. **Certificate Validation**: The `host` field must match a name in your Docker daemon's certificate. You can check your certificate's valid names with:
```bash
openssl x509 -in server-cert.pem -noout -text
```
3. **Certificate Paths**: Ensure all certificate files are readable by the user running Lazydocker
### Testing TLS Configuration
For testing purposes only, you can skip certificate verification:
```yaml
tls:
enable: true
caCertPath: "/path/to/ca.pem"
certPath: "/path/to/cert.pem"
keyPath: "/path/to/key.pem"
host: "any-name-here" # Ignored when insecureSkipVerify is true
insecureSkipVerify: true # INSECURE - only for testing!
```
### Common TLS Errors
- **"x509: certificate is valid for X, not Y"**: The `host` field doesn't match any name on the server's certificate
- **"certificate signed by unknown authority"**: The `caCertPath` is incorrect or the server's certificate wasn't signed by the specified CA
- **"no such host"**: Network connectivity issue with `DOCKER_HOST` (not a TLS config problem)
- **"tls: failed to verify certificate"**: General certificate validation failure - check all certificate paths and the `host` field
## Color Attributes:
For color attributes you can choose an array of attributes (with max one color attribute)

View file

@ -7,6 +7,7 @@ import (
"fmt"
"io"
ogLog "log"
"net/http"
"os"
"os/exec"
"strings"
@ -18,6 +19,7 @@ import (
ctxstore "github.com/docker/cli/cli/context/store"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
"github.com/docker/go-connections/tlsconfig"
"github.com/imdario/mergo"
"github.com/jesseduffield/lazydocker/pkg/commands/ssh"
"github.com/jesseduffield/lazydocker/pkg/config"
@ -97,7 +99,38 @@ func NewDockerCommand(log *logrus.Entry, osCommand *OSCommand, tr *i18n.Translat
dockerHost = dockerHostFromEnv
}
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithVersion(APIVersion), client.WithHost(dockerHost))
opts := []client.Opt{
client.FromEnv,
client.WithVersion(APIVersion),
client.WithHost(dockerHost),
}
if config.UserConfig.TLS.Enable {
tlsConfigOpts := tlsconfig.Options{
CAFile: config.UserConfig.TLS.CACertPath,
CertFile: config.UserConfig.TLS.CertPath,
KeyFile: config.UserConfig.TLS.KeyPath,
InsecureSkipVerify: config.UserConfig.TLS.InsecureSkipVerify,
ExclusiveRootPools: true,
}
customTLSConfig, err := tlsconfig.Client(tlsConfigOpts)
if err != nil {
ogLog.Fatalf("Failed to create custom TLS config: %v", err)
}
if config.UserConfig.TLS.Host != "" {
customTLSConfig.ServerName = config.UserConfig.TLS.Host
}
httpClient := &http.Client{
Transport: &http.Transport{
TLSClientConfig: customTLSConfig,
},
CheckRedirect: client.CheckRedirect,
}
opts = append(opts, client.WithHTTPClient(httpClient))
}
cli, err := client.NewClientWithOpts(opts...)
if err != nil {
ogLog.Fatal(err)
}

View file

@ -32,6 +32,9 @@ type UserConfig struct {
// hit esc or q when no confirmation panels are open
ConfirmOnQuit bool `yaml:"confirmOnQuit,omitempty"`
// TLS configuration for connecting to Docker daemon
TLS TLSConfig `yaml:"tls,omitempty"`
// Logs determines how we render/filter a container's logs
Logs LogsConfig `yaml:"logs,omitempty"`
@ -346,6 +349,35 @@ type LogsConfig struct {
Tail string `yaml:"tail,omitempty"`
}
// TLSConfig holds TLS configuration for connecting to Docker daemon
type TLSConfig struct {
// Enable TLS connections to Docker daemon
Enable bool `yaml:"enable,omitempty"`
// CACertPath is the path to the Certificate Authority (CA) certificate file
// used to verify the Docker daemon's server certificate
CACertPath string `yaml:"caCertPath,omitempty"`
// CertPath is the path to the client certificate file for mutual TLS authentication
CertPath string `yaml:"certPath,omitempty"`
// KeyPath is the path to the client private key file corresponding to the client certificate
KeyPath string `yaml:"keyPath,omitempty"`
// InsecureSkipVerify controls whether a client verifies the server's certificate chain
// and host name. If InsecureSkipVerify is true, TLS accepts any certificate presented
// by the server and any host name in that certificate. This should only be used for
// testing purposes as it makes TLS susceptible to man-in-the-middle attacks.
InsecureSkipVerify bool `yaml:"insecureSkipVerify,omitempty"`
// Host specifies the hostname or IP address expected on the Docker daemon's certificate.
// This value is used for Server Name Indication (SNI) and certificate validation.
// It must match either the Common Name (CN) or one of the Subject Alternative Names (SANs)
// in the server's certificate. Do not include protocol (tcp://) or port - just the hostname/IP.
// Example: "docker.example.com" or "192.168.1.100"
Host string `yaml:"host,omitempty"`
}
// GetDefaultConfig returns the application default configuration NOTE (to
// contributors, not users): do not default a boolean to true, because false is
// the boolean zero value and this will be ignored when parsing the user's
@ -474,6 +506,14 @@ func GetDefaultConfig() UserConfig {
Replacements: Replacements{
ImageNamePrefixes: map[string]string{},
},
TLS: TLSConfig{
Enable: false,
CACertPath: "",
CertPath: "",
KeyPath: "",
InsecureSkipVerify: false,
Host: "",
},
}
}