Skip to content

Commit 7d83c3e

Browse files
feat: reimplement proxy (#68)
* fix: update user mapping * feat: reimplement proxy * ci: run ci * fix: https and ignore redirects * test: skip CONNECT test * feat: block disallowed HTTP requests * tmp commit: seems working * fix: close connection * feat: add audit * fix: proxy logging * fix: logger * refactor: minor improvement * refactor: minor improvement * refactor: minor improvement * refactor: minor improvements * refactor: minor refactoring * fix: linter * minor fix * fix: linter
1 parent 9238fe3 commit 7d83c3e

File tree

3 files changed

+304
-532
lines changed

3 files changed

+304
-532
lines changed

e2e_tests/boundary_integration_test.go

Lines changed: 126 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ func getChildProcessPID(t *testing.T) int {
4949
return pid
5050
}
5151

52+
// This test runs boundary process with such allowed domains:
53+
// - dev.coder.com
54+
// - jsonplaceholder.typicode.com
55+
// It makes sure you can access these domains with curl tool (using both HTTP and HTTPS protocols).
56+
// Then it makes sure you can NOT access example.com domain which is not allowed (using both HTTP and HTTPS protocols).
5257
func TestBoundaryIntegration(t *testing.T) {
5358
// Find project root by looking for go.mod file
5459
projectRoot := findProjectRoot(t)
@@ -134,9 +139,9 @@ func TestBoundaryIntegration(t *testing.T) {
134139
})
135140

136141
// Test blocked domain (from inside the jail)
137-
t.Run("BlockedDomainTest", func(t *testing.T) {
142+
t.Run("HTTPBlockedDomainTest", func(t *testing.T) {
138143
// Run curl directly in the namespace using ip netns exec
139-
curlCmd := exec.Command("sudo", "sudo", "nsenter", "-t", pid, "-n", "--",
144+
curlCmd := exec.Command("sudo", "nsenter", "-t", pid, "-n", "--",
140145
"curl", "-s", "http://example.com")
141146

142147
// Capture stderr separately
@@ -150,6 +155,125 @@ func TestBoundaryIntegration(t *testing.T) {
150155
require.Contains(t, string(output), "Request Blocked by Boundary")
151156
})
152157

158+
// Test blocked domain (from inside the jail)
159+
t.Run("HTTPSBlockedDomainTest", func(t *testing.T) {
160+
_, _, _, _, configDir := util.GetUserInfo()
161+
certPath := fmt.Sprintf("%v/ca-cert.pem", configDir)
162+
163+
// Run curl directly in the namespace using ip netns exec
164+
curlCmd := exec.Command("sudo", "nsenter", "-t", pid, "-n", "--",
165+
"env", fmt.Sprintf("SSL_CERT_FILE=%v", certPath), "curl", "-s", "https://example.com")
166+
167+
// Capture stderr separately
168+
var stderr bytes.Buffer
169+
curlCmd.Stderr = &stderr
170+
output, err := curlCmd.Output()
171+
172+
if err != nil {
173+
t.Fatalf("curl command failed: %v, stderr: %s, output: %s", err, stderr.String(), string(output))
174+
}
175+
require.Contains(t, string(output), "Request Blocked by Boundary")
176+
})
177+
178+
// Gracefully close process, call cleanup methods
179+
err = boundaryCmd.Process.Signal(os.Interrupt)
180+
require.NoError(t, err, "Failed to interrupt boundary process")
181+
time.Sleep(time.Second * 1)
182+
183+
// Clean up
184+
cancel() // This will terminate the boundary process
185+
err = boundaryCmd.Wait() // Wait for process to finish
186+
if err != nil {
187+
t.Logf("Boundary process finished with error: %v", err)
188+
}
189+
190+
// Clean up binary
191+
err = os.Remove("/tmp/boundary-test")
192+
require.NoError(t, err, "Failed to remove /tmp/boundary-test")
193+
}
194+
195+
// This test runs boundary process with such allowed domains:
196+
// - example.com
197+
// It makes sure you can access this domain with curl tool (using both HTTP and HTTPS protocols).
198+
// It indirectly tests that ContentLength header is properly set, otherwise it fails.
199+
func TestContentLengthHeader(t *testing.T) {
200+
expectedResponse := `<!doctype html><html lang="en"><head><title>Example Domain</title><meta name="viewport" content="width=device-width, initial-scale=1"><style>body{background:#eee;width:60vw;margin:15vh auto;font-family:system-ui,sans-serif}h1{font-size:1.5em}div{opacity:0.8}a:link,a:visited{color:#348}</style><body><div><h1>Example Domain</h1><p>This domain is for use in documentation examples without needing permission. Avoid use in operations.<p><a href="https://iana.org/domains/example">Learn more</a></div></body></html>
201+
`
202+
203+
// Find project root by looking for go.mod file
204+
projectRoot := findProjectRoot(t)
205+
206+
// Build the boundary binary
207+
buildCmd := exec.Command("go", "build", "-o", "/tmp/boundary-test", "./cmd/...")
208+
buildCmd.Dir = projectRoot
209+
err := buildCmd.Run()
210+
require.NoError(t, err, "Failed to build boundary binary")
211+
212+
// Create context for boundary process
213+
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
214+
defer cancel()
215+
216+
// Start boundary process with sudo
217+
boundaryCmd := exec.CommandContext(ctx, "/tmp/boundary-test",
218+
"--allow", "example.com",
219+
"--log-level", "debug",
220+
"--", "/bin/bash", "-c", "/usr/bin/sleep 10 && /usr/bin/echo 'Test completed'")
221+
222+
boundaryCmd.Stdin = os.Stdin
223+
boundaryCmd.Stdout = os.Stdout
224+
boundaryCmd.Stderr = os.Stderr
225+
226+
// Start the process
227+
err = boundaryCmd.Start()
228+
require.NoError(t, err, "Failed to start boundary process")
229+
230+
// Give boundary time to start
231+
time.Sleep(2 * time.Second)
232+
233+
pidInt := getChildProcessPID(t)
234+
pid := fmt.Sprintf("%v", pidInt)
235+
236+
// Test HTTP request through boundary (from inside the jail)
237+
t.Run("HTTPRequestThroughBoundary", func(t *testing.T) {
238+
// Run curl directly in the namespace using ip netns exec
239+
curlCmd := exec.Command("sudo", "nsenter", "-t", pid, "-n", "--",
240+
"curl", "http://example.com")
241+
242+
// Capture stderr separately
243+
var stderr bytes.Buffer
244+
curlCmd.Stderr = &stderr
245+
output, err := curlCmd.Output()
246+
247+
if err != nil {
248+
t.Fatalf("curl command failed: %v, stderr: %s, output: %s", err, stderr.String(), string(output))
249+
}
250+
251+
// Verify response contains expected content
252+
require.Equal(t, expectedResponse, string(output))
253+
})
254+
255+
// Test HTTPS request through boundary (from inside the jail)
256+
t.Run("HTTPSRequestThroughBoundary", func(t *testing.T) {
257+
_, _, _, _, configDir := util.GetUserInfo()
258+
certPath := fmt.Sprintf("%v/ca-cert.pem", configDir)
259+
260+
// Run curl directly in the namespace using ip netns exec
261+
curlCmd := exec.Command("sudo", "nsenter", "-t", pid, "-n", "--",
262+
"env", fmt.Sprintf("SSL_CERT_FILE=%v", certPath), "curl", "-s", "https://example.com")
263+
264+
// Capture stderr separately
265+
var stderr bytes.Buffer
266+
curlCmd.Stderr = &stderr
267+
output, err := curlCmd.Output()
268+
269+
if err != nil {
270+
t.Fatalf("curl command failed: %v, stderr: %s, output: %s", err, stderr.String(), string(output))
271+
}
272+
273+
// Verify response contains expected content
274+
require.Equal(t, expectedResponse, string(output))
275+
})
276+
153277
// Gracefully close process, call cleanup methods
154278
err = boundaryCmd.Process.Signal(os.Interrupt)
155279
require.NoError(t, err, "Failed to interrupt boundary process")

0 commit comments

Comments
 (0)