Skip to content

Commit e109695

Browse files
authored
DNS isolation for JD and CLNodes (#1798)
* add chaosmesh debug example with Havoc for local and stage * WIP: add chaosmesh debug example with Havoc for local and stage * JD, CL node DNS isolation, update troubleshooting * review fixes
1 parent 6be35b8 commit e109695

File tree

16 files changed

+497
-4
lines changed

16 files changed

+497
-4
lines changed

book/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
- [Components Cleanup](framework/components/cleanup.md)
2626
- [Components Caching](framework/components/caching.md)
2727
- [Components Resources](framework/components/resources.md)
28+
- [Containers Network Isolation](framework/components/network_isolation.md)
2829
- [Mocking Services](framework/components/mocking.md)
2930
- [Copying Files](framework/copying_files.md)
3031
- [External Environment](framework/components/external.md)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Containers Network Isolation
2+
3+
Some components can be isolated from internet. Since some of them doesn't have `iptables` and must be accessible from local host for debugging we isolate network on DNS level.
4+
5+
JobDistributor is isolated from internet by default to prevent applying manifest changes when run in tests.
6+
7+
NodeSet DNS isolation can be controlled with a flag
8+
```
9+
[[nodesets]]
10+
# NodeSet DNS can be isolated if needed
11+
no_dns = true
12+
```

book/src/framework/components/troubleshooting.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
# Troubleshooting
22

3+
## Can't start `ctf obs u`
4+
```
5+
Error response from daemon: error while creating mount source path '/host_mnt/Users/fsldkfs/Downloads/compose/conf/provisioning/dashboards/cadvisor/cadvisor.json': mkdir /host_mnt/Users/sdfjskj/Downloads/compose/conf/provisioning: operation not permitted
6+
exit status 1
7+
```
8+
9+
#### Solution
10+
Enable Docker to access your directory
11+
```
12+
Docker Desktop -> Settings -> Resources -> File Sharing
13+
```
14+
15+
316
## Can't run `anvil`, issue with `Rosetta`
417
```
518
2024/11/27 15:20:27 ⏳ Waiting for container id 79f8a68c07cc image: f4hrenh9it/foundry:latest. Waiting for: &{Port:8546 timeout:0x14000901278 PollInterval:100ms skipInternalCheck:false}

framework/.changeset/v0.7.6.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
- Add troubleshooting for observability stack and file access
2+
- Add DNS isolation for CL node and JD + test

framework/components/clnode/clnode.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ var (
3636

3737
// Input represents Chainlink node input
3838
type Input struct {
39+
NoDNS bool `toml:"no_dns"`
3940
DbInput *postgres.Input `toml:"db" validate:"required"`
4041
Node *NodeInput `toml:"node" validate:"required"`
4142
Out *Output `toml:"out"`
@@ -252,6 +253,7 @@ func newNode(in *Input, pgOut *postgres.Output) (*NodeOut, error) {
252253
}
253254
if in.Node.HTTPPort != 0 && in.Node.P2PPort != 0 {
254255
req.HostConfigModifier = func(h *container.HostConfig) {
256+
framework.NoDNS(in.NoDNS, h)
255257
h.PortBindings = portBindings
256258
framework.ResourceLimitsFunc(h, in.Node.ContainerResources)
257259
}

framework/components/jd/jd.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ func NewJD(in *Input) (*Output, error) {
9393
},
9494
ExposedPorts: []string{bindPort},
9595
HostConfigModifier: func(h *container.HostConfig) {
96+
// JobDistributor service is isolated from internet by default!
97+
framework.NoDNS(true, h)
9698
h.PortBindings = framework.MapTheSamePort(bindPort)
9799
},
98100
Env: map[string]string{
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package networktest
2+
3+
/*
4+
This component exists purely for Docker debug purposes
5+
*/
6+
7+
import (
8+
"context"
9+
"fmt"
10+
11+
"github.com/docker/docker/api/types/container"
12+
"github.com/testcontainers/testcontainers-go"
13+
"github.com/testcontainers/testcontainers-go/wait"
14+
15+
"github.com/smartcontractkit/chainlink-testing-framework/framework"
16+
)
17+
18+
type Input struct {
19+
Name string
20+
NoDNS bool
21+
CustomNetwork bool
22+
}
23+
24+
type Output struct{}
25+
26+
// NewNetworkTest creates a minimal Alpine Linux container for network testing
27+
func NewNetworkTest(in Input) error {
28+
req := testcontainers.ContainerRequest{
29+
Name: in.Name,
30+
Image: "alpine:latest",
31+
Networks: []string{framework.DefaultNetworkName},
32+
NetworkAliases: map[string][]string{
33+
framework.DefaultNetworkName: {"networktest"},
34+
},
35+
Labels: framework.DefaultTCLabels(),
36+
WaitingFor: wait.ForLog(""),
37+
Cmd: []string{"/bin/sh", "-c", "while true; do sleep 30; done;"},
38+
}
39+
req.HostConfigModifier = func(hc *container.HostConfig) {
40+
// Remove external DNS
41+
framework.NoDNS(in.NoDNS, hc)
42+
}
43+
44+
_, err := testcontainers.GenericContainer(context.Background(), testcontainers.GenericContainerRequest{
45+
ContainerRequest: req,
46+
Started: true,
47+
})
48+
if err != nil {
49+
return fmt.Errorf("failed to start alpine container: %w", err)
50+
}
51+
return nil
52+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package networktest_test
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/stretchr/testify/require"
8+
9+
"github.com/smartcontractkit/chainlink-testing-framework/framework"
10+
"github.com/smartcontractkit/chainlink-testing-framework/framework/components/networktest"
11+
)
12+
13+
func TestNetworkIsolationRules(t *testing.T) {
14+
t.Run("can work without DNS isolation", func(t *testing.T) {
15+
name := "nettest1"
16+
err := networktest.NewNetworkTest(networktest.Input{NoDNS: false, Name: name})
17+
require.NoError(t, err)
18+
dc, err := framework.NewDockerClient()
19+
require.NoError(t, err)
20+
sOut, err := dc.ExecContainer(name, []string{"ping", "-c", "1", "google.com"})
21+
require.NoError(t, err)
22+
require.NotContains(t, sOut, "bad address")
23+
fmt.Println(sOut)
24+
})
25+
t.Run("DNS isolation works", func(t *testing.T) {
26+
name := "nettest2"
27+
err := networktest.NewNetworkTest(networktest.Input{NoDNS: true, Name: name})
28+
require.NoError(t, err)
29+
dc, err := framework.NewDockerClient()
30+
require.NoError(t, err)
31+
sOut, err := dc.ExecContainer(name, []string{"ping", "-c", "1", "google.com"})
32+
require.NoError(t, err)
33+
require.Contains(t, sOut, "bad address")
34+
fmt.Println(sOut)
35+
})
36+
}

framework/components/simple_node_set/node_set.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ type Input struct {
3030
OverrideMode string `toml:"override_mode" validate:"required,oneof=all each"`
3131
DbInput *postgres.Input `toml:"db" validate:"required"`
3232
NodeSpecs []*clnode.Input `toml:"node_specs" validate:"required"`
33+
NoDNS bool `toml:"no_dns"`
3334
Out *Output `toml:"out"`
3435
}
3536

@@ -135,6 +136,7 @@ func sharedDBSetup(in *Input, bcOut *blockchain.Output) (*Output, error) {
135136
nodeWithNodeSetPrefixName := fmt.Sprintf("%s-%s", in.Name, nodeName)
136137

137138
nodeSpec := &clnode.Input{
139+
NoDNS: in.NoDNS,
138140
DbInput: in.DbInput,
139141
Node: &clnode.NodeInput{
140142
HTTPPort: httpPortRangeStart + i,

framework/docker.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ func ResourceLimitsFunc(h *container.HostConfig, resources *ContainerResources)
412412
}
413413
}
414414

415+
// GenerateCustomPortsData generate custom ports data: exposed and forwarded port map
415416
func GenerateCustomPortsData(portsProvided []string) ([]string, nat.PortMap, error) {
416417
exposedPorts := make([]string, 0)
417418
portBindings := nat.PortMap{}
@@ -438,3 +439,10 @@ func GenerateCustomPortsData(portsProvided []string) ([]string, nat.PortMap, err
438439
exposedPorts = append(exposedPorts, customPorts...)
439440
return exposedPorts, portBindings, nil
440441
}
442+
443+
// NoDNS removes default DNS server and sets it to localhost
444+
func NoDNS(noDNS bool, hc *container.HostConfig) {
445+
if noDNS {
446+
hc.DNS = []string{"127.0.0.1"}
447+
}
448+
}

0 commit comments

Comments
 (0)