mirror of
https://github.com/drone-plugins/drone-docker.git
synced 2026-07-16 16:21:18 +08:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e44c053dcc |
@@ -123,8 +123,8 @@ store**, so base-image pulls fail with
|
|||||||
`x509: certificate signed by unknown authority` unless that CA is trusted.
|
`x509: certificate signed by unknown authority` unless that CA is trusted.
|
||||||
|
|
||||||
Set the `HARNESS_CA_PATH` environment variable to a PEM CA (bundle) file and the
|
Set the `HARNESS_CA_PATH` environment variable to a PEM CA (bundle) file and the
|
||||||
plugin installs it into the host trust store **before starting the Docker
|
plugin installs it into the host trust store **before any HTTPS** (registry
|
||||||
daemon**:
|
wrapper auth such as GCP STS, and before starting the Docker daemon):
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
@@ -146,18 +146,22 @@ Behavior:
|
|||||||
`update-ca-certificates` / `update-ca-trust`. It also appends the CA directly
|
`update-ca-certificates` / `update-ca-trust`. It also appends the CA directly
|
||||||
to the consolidated bundle (`/etc/ssl/certs/ca-certificates.crt` or the RHEL
|
to the consolidated bundle (`/etc/ssl/certs/ca-certificates.crt` or the RHEL
|
||||||
equivalent) so trust holds even on minimal images without a refresh tool.
|
equivalent) so trust holds even on minimal images without a refresh tool.
|
||||||
- **Windows** — imports the CA into the machine trust store via
|
- **Windows** — imports the CA into `LocalMachine\Root` via the Windows
|
||||||
`certutil -addstore -f Root`.
|
CryptoAPI (`crypt32.dll`). This works on Nano Server images that lack
|
||||||
|
`certutil` / PowerShell.
|
||||||
- **macOS / other** — logged no-op (not currently supported).
|
- **macOS / other** — logged no-op (not currently supported).
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
|
|
||||||
|
- Registry wrappers (`plugins/gcr`, `gar`, `acr`, `ecr`) call the same install
|
||||||
|
before their pre-docker HTTPS auth (e.g. `sts.googleapis.com` token exchange).
|
||||||
- It is **best-effort and idempotent**: when `HARNESS_CA_PATH` is unset, the file
|
- It is **best-effort and idempotent**: when `HARNESS_CA_PATH` is unset, the file
|
||||||
is missing, or the file is empty, the plugin logs and continues. Re-running the
|
is missing, or the file is empty, the plugin logs and continues. Re-running the
|
||||||
step will not duplicate the CA in the bundle.
|
step will not duplicate the CA in the bundle.
|
||||||
- The CA is trusted for the daemon's own registry TLS (base-image pulls, cache
|
- The CA is trusted for the daemon's own registry TLS (base-image pulls, cache
|
||||||
endpoints). To make the CA available to `RUN` steps inside the build, also pass
|
endpoints) and for Go TLS clients in the plugin process. To make the CA
|
||||||
it as needed via the Dockerfile / build args.
|
available to `RUN` steps inside the build, also pass it as needed via the
|
||||||
|
Dockerfile / build args.
|
||||||
- This is separate from the proxy build args
|
- This is separate from the proxy build args
|
||||||
(`http_proxy`/`https_proxy`/`no_proxy`), which the plugin already injects from
|
(`http_proxy`/`https_proxy`/`no_proxy`), which the plugin already injects from
|
||||||
the environment (including `HARNESS_`-prefixed variants).
|
the environment (including `HARNESS_`-prefixed variants).
|
||||||
|
|||||||
+4
-4
@@ -31,7 +31,7 @@ func TestTrustHarnessCA_Unset(t *testing.T) {
|
|||||||
os.Unsetenv("HARNESS_CA_PATH")
|
os.Unsetenv("HARNESS_CA_PATH")
|
||||||
_, calls := withStubbedInstall(t)
|
_, calls := withStubbedInstall(t)
|
||||||
|
|
||||||
trustHarnessCA()
|
TrustHarnessCA()
|
||||||
|
|
||||||
if *calls != 0 {
|
if *calls != 0 {
|
||||||
t.Fatalf("expected installer not to be called when HARNESS_CA_PATH is unset, got %d calls", *calls)
|
t.Fatalf("expected installer not to be called when HARNESS_CA_PATH is unset, got %d calls", *calls)
|
||||||
@@ -44,7 +44,7 @@ func TestTrustHarnessCA_MissingFile(t *testing.T) {
|
|||||||
defer os.Unsetenv("HARNESS_CA_PATH")
|
defer os.Unsetenv("HARNESS_CA_PATH")
|
||||||
_, calls := withStubbedInstall(t)
|
_, calls := withStubbedInstall(t)
|
||||||
|
|
||||||
trustHarnessCA()
|
TrustHarnessCA()
|
||||||
|
|
||||||
if *calls != 0 {
|
if *calls != 0 {
|
||||||
t.Fatalf("expected installer not to be called when CA file is missing, got %d calls", *calls)
|
t.Fatalf("expected installer not to be called when CA file is missing, got %d calls", *calls)
|
||||||
@@ -60,7 +60,7 @@ func TestTrustHarnessCA_EmptyFile(t *testing.T) {
|
|||||||
defer os.Unsetenv("HARNESS_CA_PATH")
|
defer os.Unsetenv("HARNESS_CA_PATH")
|
||||||
_, calls := withStubbedInstall(t)
|
_, calls := withStubbedInstall(t)
|
||||||
|
|
||||||
trustHarnessCA()
|
TrustHarnessCA()
|
||||||
|
|
||||||
if *calls != 0 {
|
if *calls != 0 {
|
||||||
t.Fatalf("expected installer not to be called for whitespace-only CA, got %d calls", *calls)
|
t.Fatalf("expected installer not to be called for whitespace-only CA, got %d calls", *calls)
|
||||||
@@ -76,7 +76,7 @@ func TestTrustHarnessCA_ValidFile(t *testing.T) {
|
|||||||
defer os.Unsetenv("HARNESS_CA_PATH")
|
defer os.Unsetenv("HARNESS_CA_PATH")
|
||||||
captured, calls := withStubbedInstall(t)
|
captured, calls := withStubbedInstall(t)
|
||||||
|
|
||||||
trustHarnessCA()
|
TrustHarnessCA()
|
||||||
|
|
||||||
if *calls != 1 {
|
if *calls != 1 {
|
||||||
t.Fatalf("expected installer to be called once for a valid CA, got %d calls", *calls)
|
t.Fatalf("expected installer to be called once for a valid CA, got %d calls", *calls)
|
||||||
|
|||||||
@@ -52,6 +52,10 @@ func main() {
|
|||||||
godotenv.Load(env)
|
godotenv.Load(env)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Must run before Azure / ACR HTTPS auth: this binary does auth before
|
||||||
|
// spawning drone-docker, which is where TrustHarnessCA also runs for the daemon.
|
||||||
|
docker.TrustHarnessCA()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
repo = getenv("PLUGIN_REPO")
|
repo = getenv("PLUGIN_REPO")
|
||||||
registry = getenv("PLUGIN_REGISTRY")
|
registry = getenv("PLUGIN_REGISTRY")
|
||||||
|
|||||||
@@ -24,6 +24,10 @@ func main() {
|
|||||||
godotenv.Load(env)
|
godotenv.Load(env)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Install egress CA before any TLS in this process (including the Docker
|
||||||
|
// daemon started from Plugin.Exec).
|
||||||
|
docker.TrustHarnessCA()
|
||||||
|
|
||||||
app := cli.NewApp()
|
app := cli.NewApp()
|
||||||
app.Name = "docker plugin"
|
app.Name = "docker plugin"
|
||||||
app.Usage = "docker plugin"
|
app.Usage = "docker plugin"
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ func main() {
|
|||||||
godotenv.Load(env)
|
godotenv.Load(env)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Must run before AWS / ECR HTTPS auth: this binary does auth before
|
||||||
|
// spawning drone-docker, which is where TrustHarnessCA also runs for the daemon.
|
||||||
|
docker.TrustHarnessCA()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
repo = getenv("PLUGIN_REPO")
|
repo = getenv("PLUGIN_REPO")
|
||||||
registry = getenv("PLUGIN_REGISTRY")
|
registry = getenv("PLUGIN_REGISTRY")
|
||||||
|
|||||||
@@ -49,6 +49,10 @@ func loadConfig() Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Must run before STS / oauth HTTPS: this binary does auth before spawning
|
||||||
|
// drone-docker, which is where TrustHarnessCA also runs for the daemon.
|
||||||
|
docker.TrustHarnessCA()
|
||||||
|
|
||||||
idToken := getenv("PLUGIN_OIDC_TOKEN_ID")
|
idToken := getenv("PLUGIN_OIDC_TOKEN_ID")
|
||||||
projectId := getenv("PLUGIN_PROJECT_NUMBER")
|
projectId := getenv("PLUGIN_PROJECT_NUMBER")
|
||||||
poolId := getenv("PLUGIN_POOL_ID")
|
poolId := getenv("PLUGIN_POOL_ID")
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ func loadConfig() Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Must run before STS / oauth HTTPS: this binary does auth before spawning
|
||||||
|
// drone-docker, which is where TrustHarnessCA also runs for the daemon.
|
||||||
|
docker.TrustHarnessCA()
|
||||||
|
|
||||||
idToken := getenv("PLUGIN_OIDC_TOKEN_ID")
|
idToken := getenv("PLUGIN_OIDC_TOKEN_ID")
|
||||||
projectId := getenv("PLUGIN_PROJECT_NUMBER")
|
projectId := getenv("PLUGIN_PROJECT_NUMBER")
|
||||||
poolId := getenv("PLUGIN_POOL_ID")
|
poolId := getenv("PLUGIN_POOL_ID")
|
||||||
|
|||||||
@@ -132,14 +132,6 @@ type (
|
|||||||
|
|
||||||
// Exec executes the plugin step
|
// Exec executes the plugin step
|
||||||
func (p Plugin) Exec() error {
|
func (p Plugin) Exec() error {
|
||||||
// Trust the Harness egress-proxy CA (if HARNESS_CA_PATH is set) BEFORE the
|
|
||||||
// daemon starts. The Docker daemon and its embedded BuildKit verify registry
|
|
||||||
// TLS against the host system trust store; when traffic goes through the
|
|
||||||
// TLS-intercepting egress proxy, the presented cert is signed by the Harness
|
|
||||||
// CA and must be trusted here or base-image pulls fail with an x509
|
|
||||||
// "unknown authority" error.
|
|
||||||
trustHarnessCA()
|
|
||||||
|
|
||||||
// start the Docker daemon server
|
// start the Docker daemon server
|
||||||
if !p.Daemon.Disabled {
|
if !p.Daemon.Disabled {
|
||||||
p.startDaemon()
|
p.startDaemon()
|
||||||
@@ -583,17 +575,23 @@ func getSecretCmdArg(kvp string, file bool) (string, error) {
|
|||||||
return fmt.Sprintf("id=%s,env=%s", key, value), nil
|
return fmt.Sprintf("id=%s,env=%s", key, value), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// trustHarnessCA installs the Harness egress-proxy CA into the host trust store
|
// TrustHarnessCA installs the Harness egress-proxy CA into the host trust store
|
||||||
// so the Docker daemon / embedded BuildKit trust the TLS-intercepting proxy when
|
// so the Docker daemon / embedded BuildKit (and this process's Go TLS clients)
|
||||||
// pulling base images. It is driven by HARNESS_CA_PATH (path to a PEM CA bundle)
|
// trust the TLS-intercepting proxy. It is driven by HARNESS_CA_PATH (path to a
|
||||||
// and is a best-effort no-op when the var is unset, the file is missing, or the
|
// PEM CA bundle) and is a best-effort no-op when the var is unset, the file is
|
||||||
// platform isn't supported — build failures are surfaced later by docker itself.
|
// missing, or the platform isn't supported — build failures are surfaced later
|
||||||
|
// by docker itself.
|
||||||
|
//
|
||||||
|
// Call from each binary's main (after loading PLUGIN_ENV_FILE) before any HTTPS:
|
||||||
|
// Go caches SystemCertPool on first use, and registry wrappers (gcr/gar/acr/ecr)
|
||||||
|
// perform auth HTTPS before spawning drone-docker.
|
||||||
|
//
|
||||||
// The platform-specific installation is provided by installHarnessCA (see
|
// The platform-specific installation is provided by installHarnessCA (see
|
||||||
// ca_linux.go / ca_windows.go / ca_other.go); it is indirected through
|
// ca_linux.go / ca_windows.go / ca_other.go); it is indirected through
|
||||||
// installHarnessCAFn so tests can stub the actual system-trust write.
|
// installHarnessCAFn so tests can stub the actual system-trust write.
|
||||||
var installHarnessCAFn = installHarnessCA
|
var installHarnessCAFn = installHarnessCA
|
||||||
|
|
||||||
func trustHarnessCA() {
|
func TrustHarnessCA() {
|
||||||
caPath := os.Getenv("HARNESS_CA_PATH")
|
caPath := os.Getenv("HARNESS_CA_PATH")
|
||||||
if caPath == "" {
|
if caPath == "" {
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user