Skip to content

Commit 3f69925

Browse files
authored
Merge pull request #354 from depot/billy/feat/req-ipc-allow-builder-ip
feat: allowlist builder IPs by telling agentd over HTTP
2 parents 06e4011 + 2635232 commit 3f69925

File tree

5 files changed

+128
-4
lines changed

5 files changed

+128
-4
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ require (
5656

5757
require (
5858
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
59-
github.com/Microsoft/go-winio v0.6.0 // indirect
59+
github.com/Microsoft/go-winio v0.6.1 // indirect
6060
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d // indirect
6161
github.com/agext/levenshtein v1.2.3 // indirect
6262
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ
5858
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
5959
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
6060
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
61-
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
62-
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
61+
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
62+
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
6363
github.com/Microsoft/hcsshim v0.9.8 h1:lf7xxK2+Ikbj9sVf2QZsouGjRjEp2STj1yDHgoVtU5k=
6464
github.com/Microsoft/hcsshim v0.9.8/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
6565
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=

pkg/helpers/gha.go

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package helpers
22

3-
import "os"
3+
import (
4+
"os"
5+
"runtime"
6+
)
47

58
// If the CLI is running inside a Depot GitHub Actions runner, restore the original
69
// GitHub Actions cache URL so that the remote BuildKit doesn't attempt to use the internal cache.
@@ -17,3 +20,35 @@ func FixGitHubActionsCacheEnv() {
1720
os.Setenv("ACTIONS_RESULTS_URL", original)
1821
}
1922
}
23+
24+
// IsDepotGitHubActionsRunner detects Depot runners by checking for agentd binary in OS-specific locations.
25+
func IsDepotGitHubActionsRunner() bool {
26+
var agentdPaths []string
27+
28+
switch runtime.GOOS {
29+
case "windows":
30+
agentdPaths = []string{
31+
"C:\\ProgramData\\Agentd\\agentd-service.exe",
32+
}
33+
case "darwin":
34+
agentdPaths = []string{
35+
"/usr/local/bin/agentd",
36+
}
37+
case "linux":
38+
agentdPaths = []string{
39+
"/usr/local/bin/agentd",
40+
}
41+
default:
42+
agentdPaths = []string{
43+
"/usr/local/bin/agentd",
44+
}
45+
}
46+
47+
for _, path := range agentdPaths {
48+
if _, err := os.Stat(path); err == nil {
49+
return true
50+
}
51+
}
52+
53+
return false
54+
}

pkg/machine/agentd_client.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package machine
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/json"
7+
"fmt"
8+
"net"
9+
"net/http"
10+
"strings"
11+
"time"
12+
)
13+
14+
type AllowIPRequest struct {
15+
AllowIPs []string `json:"allowIPs"`
16+
}
17+
18+
func AllowBuilderIPViaHTTP(ctx context.Context, endpoint string) error {
19+
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
20+
defer cancel()
21+
22+
ip, err := extractIPFromEndpoint(endpoint)
23+
if err != nil {
24+
return fmt.Errorf("failed to extract IP from endpoint: %w", err)
25+
}
26+
27+
req := AllowIPRequest{
28+
AllowIPs: []string{ip},
29+
}
30+
31+
reqJSON, err := json.Marshal(req)
32+
if err != nil {
33+
return fmt.Errorf("failed to marshal request: %w", err)
34+
}
35+
36+
client := &http.Client{
37+
Timeout: 30 * time.Second,
38+
}
39+
40+
httpReq, err := http.NewRequestWithContext(ctx, "POST", "http://127.0.0.1:912/", bytes.NewBuffer(reqJSON))
41+
if err != nil {
42+
return fmt.Errorf("failed to create HTTP request: %w", err)
43+
}
44+
httpReq.Header.Set("Content-Type", "application/json")
45+
46+
resp, err := client.Do(httpReq)
47+
if err != nil {
48+
// The HTTP server only runs if the egress filter is enabled, so don't worry about not being able to connect
49+
return nil
50+
}
51+
defer resp.Body.Close()
52+
53+
var response map[string]any
54+
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
55+
return fmt.Errorf("failed to decode HTTP response: %w", err)
56+
}
57+
58+
if success, ok := response["success"].(bool); ok && success {
59+
return nil
60+
}
61+
62+
if errMsg, ok := response["error"].(string); ok {
63+
return fmt.Errorf("HTTP request failed: %s", errMsg)
64+
}
65+
66+
return fmt.Errorf("unexpected HTTP response: %v", response)
67+
}
68+
69+
func extractIPFromEndpoint(endpoint string) (string, error) {
70+
endpoint = strings.TrimPrefix(endpoint, "tcp://")
71+
72+
host, _, err := net.SplitHostPort(endpoint)
73+
if err != nil {
74+
return "", fmt.Errorf("failed to split host and port: %w", err)
75+
}
76+
77+
if net.ParseIP(host) == nil {
78+
return "", fmt.Errorf("not a valid IP address: %s", host)
79+
}
80+
81+
return host, nil
82+
}

pkg/machine/machine.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"connectrpc.com/connect"
1313
"github.com/depot/cli/pkg/api"
1414
"github.com/depot/cli/pkg/cleanup"
15+
"github.com/depot/cli/pkg/helpers"
1516
cliv1 "github.com/depot/cli/pkg/proto/depot/cli/v1"
1617
"github.com/depot/cli/pkg/proto/depot/cli/v1/cliv1connect"
1718
"github.com/moby/buildkit/client"
@@ -81,6 +82,12 @@ func Acquire(ctx context.Context, buildID, token, platform string) (*Machine, er
8182
case *cliv1.GetBuildKitConnectionResponse_Active:
8283
m.Addr = connection.Active.Endpoint
8384
m.ServerName = connection.Active.ServerName
85+
86+
if helpers.IsDepotGitHubActionsRunner() {
87+
// if this is failing, we can check what the actual issue is by ssh'ing into the GHA runner machine
88+
_ = AllowBuilderIPViaHTTP(ctx, m.Addr)
89+
}
90+
8491
// When testing locally, we don't have TLS certs.
8592
if connection.Active.CaCert == nil || connection.Active.Cert == nil {
8693
return m, nil

0 commit comments

Comments
 (0)