Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,11 @@ func Run() {
Usage: "Buildkit response header timeout override. Default value is 30s",
EnvVar: "PLUGIN_BUILDKIT_RESPONSE_HEADER_TIMEOUT",
},
cli.StringFlag{
Name: "buildkit-ca-cert-path",
Usage: "Path to CA certificate bundle to copy into the BuildKit container. Enables TLS verification with custom/corporate CAs for DLC S3 endpoints.",
EnvVar: "PLUGIN_BUILDKIT_CA_CERT_PATH",
},
cli.StringFlag{
Name: "harness-self-hosted-s3-access-key",
Usage: "build target",
Expand Down Expand Up @@ -568,6 +573,7 @@ func run(c *cli.Context) error {
BuildkitVersion: c.String("buildkit-version"),
BuildkitTLSHandshakeTimeout: c.String("buildkit-tls-handshake-timeout"),
BuildkitResponseHeaderTimeout: c.String("buildkit-response-header-timeout"),
CACertPath: c.String("buildkit-ca-cert-path"),
},
BaseImageRegistry: c.String("docker.baseimageregistry"),
BaseImageUsername: c.String("docker.baseimageusername"),
Expand Down
2 changes: 1 addition & 1 deletion buildkit/version.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"buildkit_version": "harness/buildkit:1.0.16"
"buildkit_version": "harness/buildkit:1.0.16-debug1"
}
131 changes: 130 additions & 1 deletion docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package docker

import (
"bytes"
"crypto/x509"
"encoding/base64"
"encoding/json"
"encoding/pem"
"fmt"
"os"
"os/exec"
Expand Down Expand Up @@ -33,7 +35,7 @@ type (
IPv6 bool // Docker daemon IPv6 networking
RegistryType drone.RegistryType // Docker registry type
ArtifactRegistry string // Docker registry where artifact can be viewed
RetryCount int // Number of retry attempts to reach Docker daemon
RetryCount int // Number of retry attempts to reach Docker daemon
}

Builder struct {
Expand All @@ -48,6 +50,7 @@ type (
BuildkitVersion string // Buildkit version
BuildkitTLSHandshakeTimeout string // Buildkit TLS handshake timeout
BuildkitResponseHeaderTimeout string // Buildkit response header timeout
CACertPath string // Path to CA cert bundle to propagate into BuildKit container
}

// Login defines Docker login parameters.
Expand Down Expand Up @@ -380,9 +383,21 @@ func (p Plugin) Exec() error {
}

removeCmd := cmdRemoveBuildx(p.Builder.Name)
var stopLogStream func()
defer func() {
if stopLogStream != nil {
stopLogStream()
}
if p.Builder.Driver == dockerContainerDriver {
dumpBuildKitLogs(p.Builder.Name)
}
removeCmd.Run()
}()

if p.Builder.Driver == dockerContainerDriver {
propagateCACertsToBuiltkit(p.Builder)
stopLogStream = streamBuildKitLogs(p.Builder.Name)
}
}

// Enforce mutual exclusivity: Bake mode and Push-only mode cannot be used together
Expand Down Expand Up @@ -1261,3 +1276,117 @@ func (p Plugin) pushOnly() error {

return nil
}

const buildkitCertPath = "/etc/ssl/certs/ca-certificates.crt"

func propagateCACertsToBuiltkit(builder Builder) {
srcPath := builder.CACertPath
if srcPath == "" {
srcPath = buildkitCertPath
}

info, err := os.Stat(srcPath)
if err != nil {
fmt.Printf("[CACert] CA cert bundle not found at %s: %v\n", srcPath, err)
if builder.CACertPath != "" {
fmt.Printf("[CACert] WARNING: PLUGIN_BUILDKIT_CA_CERT_PATH was explicitly set to %s but the file does not exist\n", builder.CACertPath)
}
return
}
fmt.Printf("[CACert] Found CA cert bundle at %s (size=%d bytes)\n", srcPath, info.Size())

data, err := os.ReadFile(srcPath)
if err != nil {
fmt.Printf("[CACert] Failed to read CA cert bundle: %v\n", err)
return
}
logCertBundleSummary(srcPath, data)

containerName := fmt.Sprintf("buildx_buildkit_%s0", builder.Name)
fmt.Printf("[CACert] Copying CA cert bundle from %s to %s:%s\n", srcPath, containerName, buildkitCertPath)

cmd := exec.Command(dockerExe, "cp", srcPath, containerName+":"+buildkitCertPath)
output, err := cmd.CombinedOutput()
if err != nil {
fmt.Printf("[CACert] WARNING: Failed to copy CA certs to BuildKit container: %v, output: %s\n", err, string(output))
return
}
fmt.Printf("[CACert] Successfully copied CA cert bundle to BuildKit container %s\n", containerName)
}

func logCertBundleSummary(path string, data []byte) {
var totalCerts int
rest := data
for {
var block *pem.Block
block, rest = pem.Decode(rest)
if block == nil {
break
}
if block.Type == "CERTIFICATE" {
totalCerts++
cert, err := x509.ParseCertificate(block.Bytes)
if err == nil && totalCerts <= 3 {
fmt.Printf("[CACert] cert #%d: Subject=%s Issuer=%s\n", totalCerts, cert.Subject, cert.Issuer)
}
}
}
fmt.Printf("[CACert] Bundle %s contains %d certificates total\n", path, totalCerts)

systemPool, err := x509.SystemCertPool()
if err != nil {
fmt.Printf("[CACert] Could not load system cert pool in plugin container: %v\n", err)
} else {
fmt.Printf("[CACert] Plugin container system cert pool has %d certificates\n", len(systemPool.Subjects()))
}
}

const buildkitLogFile = "/harness/buildkit-debug.log"

func streamBuildKitLogs(builderName string) func() {
containerName := fmt.Sprintf("buildx_buildkit_%s0", builderName)
fmt.Printf("[BuildKitLogs] Starting live log stream from %s to %s\n", containerName, buildkitLogFile)

logFile, err := os.Create(buildkitLogFile)
if err != nil {
fmt.Printf("[BuildKitLogs] WARNING: Failed to create %s: %v\n", buildkitLogFile, err)
return func() {}
}

cmd := exec.Command(dockerExe, "logs", "-f", containerName)
cmd.Stdout = logFile
cmd.Stderr = logFile

if err := cmd.Start(); err != nil {
fmt.Printf("[BuildKitLogs] WARNING: Failed to start log streaming: %v\n", err)
logFile.Close()
return func() {}
}

fmt.Printf("[BuildKitLogs] Live streaming started (pid=%d) → %s\n", cmd.Process.Pid, buildkitLogFile)

return func() {
cmd.Process.Kill()
cmd.Wait()
logFile.Close()
fmt.Printf("[BuildKitLogs] Live streaming stopped\n")
}
}

func dumpBuildKitLogs(builderName string) {
containerName := fmt.Sprintf("buildx_buildkit_%s0", builderName)
fmt.Printf("[BuildKitLogs] Dumping final logs from container %s to %s\n", containerName, buildkitLogFile)

cmd := exec.Command(dockerExe, "logs", containerName)
output, err := cmd.CombinedOutput()
if err != nil {
fmt.Printf("[BuildKitLogs] WARNING: Failed to get logs from %s: %v\n", containerName, err)
return
}

if err := os.WriteFile(buildkitLogFile, output, 0644); err != nil {
fmt.Printf("[BuildKitLogs] WARNING: Failed to write logs to %s: %v\n", buildkitLogFile, err)
return
}
fmt.Printf("[BuildKitLogs] Successfully wrote %d bytes to %s\n", len(output), buildkitLogFile)
}