mirror of
https://github.com/drone-plugins/drone-docker.git
synced 2026-07-16 16:21:18 +08:00
feat: [CI-23743]: call TrustHarnessCA before wrapper auth + export for reuse
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> AI-Session-Id: 6ea09391-f44a-4dcd-9618-f17586946b96 AI-Tool: claude-code AI-Model: unknown
This commit is contained in:
@@ -123,8 +123,8 @@ store**, so base-image pulls fail with
|
||||
`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
|
||||
plugin installs it into the host trust store **before starting the Docker
|
||||
daemon**:
|
||||
plugin installs it into the host trust store **before any HTTPS** (registry
|
||||
wrapper auth such as GCP STS, and before starting the Docker daemon):
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
@@ -146,18 +146,22 @@ Behavior:
|
||||
`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
|
||||
equivalent) so trust holds even on minimal images without a refresh tool.
|
||||
- **Windows** — imports the CA into the machine trust store via
|
||||
`certutil -addstore -f Root`.
|
||||
- **Windows** — imports the CA into `LocalMachine\Root` via the Windows
|
||||
CryptoAPI (`crypt32.dll`). This works on Nano Server images that lack
|
||||
`certutil` / PowerShell.
|
||||
- **macOS / other** — logged no-op (not currently supported).
|
||||
|
||||
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
|
||||
is missing, or the file is empty, the plugin logs and continues. Re-running the
|
||||
step will not duplicate the CA in the bundle.
|
||||
- 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
|
||||
it as needed via the Dockerfile / build args.
|
||||
endpoints) and for Go TLS clients in the plugin process. To make the CA
|
||||
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
|
||||
(`http_proxy`/`https_proxy`/`no_proxy`), which the plugin already injects from
|
||||
the environment (including `HARNESS_`-prefixed variants).
|
||||
|
||||
+4
-4
@@ -31,7 +31,7 @@ func TestTrustHarnessCA_Unset(t *testing.T) {
|
||||
os.Unsetenv("HARNESS_CA_PATH")
|
||||
_, calls := withStubbedInstall(t)
|
||||
|
||||
trustHarnessCA()
|
||||
TrustHarnessCA()
|
||||
|
||||
if *calls != 0 {
|
||||
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")
|
||||
_, calls := withStubbedInstall(t)
|
||||
|
||||
trustHarnessCA()
|
||||
TrustHarnessCA()
|
||||
|
||||
if *calls != 0 {
|
||||
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")
|
||||
_, calls := withStubbedInstall(t)
|
||||
|
||||
trustHarnessCA()
|
||||
TrustHarnessCA()
|
||||
|
||||
if *calls != 0 {
|
||||
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")
|
||||
captured, calls := withStubbedInstall(t)
|
||||
|
||||
trustHarnessCA()
|
||||
TrustHarnessCA()
|
||||
|
||||
if *calls != 1 {
|
||||
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)
|
||||
}
|
||||
|
||||
// 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 (
|
||||
repo = getenv("PLUGIN_REPO")
|
||||
registry = getenv("PLUGIN_REGISTRY")
|
||||
|
||||
@@ -24,6 +24,10 @@ func main() {
|
||||
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.Name = "docker plugin"
|
||||
app.Usage = "docker plugin"
|
||||
|
||||
@@ -30,6 +30,10 @@ func main() {
|
||||
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 (
|
||||
repo = getenv("PLUGIN_REPO")
|
||||
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")
|
||||
projectId := getenv("PLUGIN_PROJECT_NUMBER")
|
||||
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")
|
||||
projectId := getenv("PLUGIN_PROJECT_NUMBER")
|
||||
poolId := getenv("PLUGIN_POOL_ID")
|
||||
|
||||
@@ -132,14 +132,6 @@ type (
|
||||
|
||||
// Exec executes the plugin step
|
||||
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
|
||||
if !p.Daemon.Disabled {
|
||||
p.startDaemon()
|
||||
@@ -583,17 +575,23 @@ func getSecretCmdArg(kvp string, file bool) (string, error) {
|
||||
return fmt.Sprintf("id=%s,env=%s", key, value), nil
|
||||
}
|
||||
|
||||
// trustHarnessCA installs the Harness egress-proxy CA into the host trust store
|
||||
// so the Docker daemon / embedded BuildKit trust the TLS-intercepting proxy when
|
||||
// pulling base images. It is driven by HARNESS_CA_PATH (path to a PEM CA bundle)
|
||||
// and is a best-effort no-op when the var is unset, the file is missing, or the
|
||||
// platform isn't supported — build failures are surfaced later by docker itself.
|
||||
// TrustHarnessCA installs the Harness egress-proxy CA into the host trust store
|
||||
// so the Docker daemon / embedded BuildKit (and this process's Go TLS clients)
|
||||
// trust the TLS-intercepting proxy. It is driven by HARNESS_CA_PATH (path to a
|
||||
// PEM CA bundle) and is a best-effort no-op when the var is unset, the file is
|
||||
// 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
|
||||
// ca_linux.go / ca_windows.go / ca_other.go); it is indirected through
|
||||
// installHarnessCAFn so tests can stub the actual system-trust write.
|
||||
var installHarnessCAFn = installHarnessCA
|
||||
|
||||
func trustHarnessCA() {
|
||||
func TrustHarnessCA() {
|
||||
caPath := os.Getenv("HARNESS_CA_PATH")
|
||||
if caPath == "" {
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user