Repository navigation
Expand file tree
/
Copy pathca_linux.go
More file actions
110 lines (100 loc) · 3.46 KB
/
Copy pathca_linux.go
File metadata and controls
110 lines (100 loc) · 3.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
//go:build linux
// +build linux
package docker
import (
"bytes"
"fmt"
"os"
"os/exec"
"path/filepath"
)
// anchorCandidate is a distro CA anchor directory plus the tool that refreshes
// the consolidated bundle from it.
type anchorCandidate struct {
dir string
refresh []string
}
// linuxAnchorCandidates and linuxBundleCandidates are package vars (not consts)
// so tests can point them at a temp trust store. Order matters: the first
// existing entry wins for the anchor install.
var linuxAnchorCandidates = []anchorCandidate{
{"/usr/local/share/ca-certificates", []string{"update-ca-certificates"}}, // Debian/Ubuntu/Alpine
{"/etc/pki/ca-trust/source/anchors", []string{"update-ca-trust", "extract"}}, // RHEL/CentOS/Fedora
}
var linuxBundleCandidates = []string{
"/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Alpine
"/etc/pki/tls/certs/ca-bundle.crt", // RHEL/CentOS
}
// installHarnessCA drops the CA into the distro anchor directory and refreshes
// the system bundle. It also appends directly to the consolidated bundle so
// trust is effective even on images that lack update-ca-certificates (e.g.
// minimal distros); the Docker daemon and Go's crypto/x509 read from that
// bundle. Best-effort: failures are logged, never fatal.
func installHarnessCA(caPEM []byte) {
anchorCandidates := linuxAnchorCandidates
installedViaAnchor := false
for _, c := range anchorCandidates {
if _, err := os.Stat(c.dir); err != nil {
continue
}
dst := filepath.Join(c.dir, "harness-egress-ca.crt")
if err := os.WriteFile(dst, caPEM, 0644); err != nil {
fmt.Printf("Could not write Harness CA to %s: %s\n", dst, err)
continue
}
if _, err := exec.LookPath(c.refresh[0]); err != nil {
continue
}
cmd := exec.Command(c.refresh[0], c.refresh[1:]...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
fmt.Printf("Warning: %s failed: %s\n", c.refresh[0], err)
continue
}
fmt.Printf("Installed Harness egress CA into %s and refreshed system trust store.\n", c.dir)
installedViaAnchor = true
break
}
// Belt-and-suspenders: append to the consolidated bundle(s) directly so the
// CA is trusted even when no refresh tool exists or the anchor step failed.
bundleCandidates := linuxBundleCandidates
appended := false
for _, bundle := range bundleCandidates {
if _, err := os.Stat(bundle); err != nil {
continue
}
if bundleContainsCA(bundle, caPEM) {
appended = true
continue
}
f, err := os.OpenFile(bundle, os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
fmt.Printf("Could not append Harness CA to %s: %s\n", bundle, err)
continue
}
payload := caPEM
if !bytes.HasPrefix(payload, []byte("\n")) {
payload = append([]byte("\n"), payload...)
}
if _, err := f.Write(payload); err != nil {
fmt.Printf("Could not append Harness CA to %s: %s\n", bundle, err)
} else {
fmt.Printf("Appended Harness egress CA to %s.\n", bundle)
appended = true
}
f.Close()
}
if !installedViaAnchor && !appended {
fmt.Println("Warning: could not install the Harness egress CA into any known trust store location; base-image pulls through the egress proxy may fail with x509 errors.")
}
}
// bundleContainsCA reports whether the CA bytes are already present in the
// bundle, to keep the step idempotent across retries.
func bundleContainsCA(bundle string, caPEM []byte) bool {
existing, err := os.ReadFile(bundle)
if err != nil {
return false
}
return bytes.Contains(existing, bytes.TrimSpace(caPEM))
}