|
| 1 | +// Copyright (c) 2024 ScyllaDB. |
| 2 | + |
| 3 | +package scyllacluster |
| 4 | + |
| 5 | +import ( |
| 6 | + "context" |
| 7 | + "net" |
| 8 | + "strings" |
| 9 | + |
| 10 | + g "github.com/onsi/ginkgo/v2" |
| 11 | + o "github.com/onsi/gomega" |
| 12 | + scyllav1 "github.com/scylladb/scylla-operator/pkg/api/scylla/v1" |
| 13 | + "github.com/scylladb/scylla-operator/pkg/controllerhelpers" |
| 14 | + "github.com/scylladb/scylla-operator/pkg/naming" |
| 15 | + "github.com/scylladb/scylla-operator/test/e2e/framework" |
| 16 | + "github.com/scylladb/scylla-operator/test/e2e/tools" |
| 17 | + "github.com/scylladb/scylla-operator/test/e2e/utils" |
| 18 | + linuxnetutils "github.com/scylladb/scylla-operator/test/e2e/utils/linux/net" |
| 19 | + scyllaclusterverification "github.com/scylladb/scylla-operator/test/e2e/utils/verification/scyllacluster" |
| 20 | + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
| 21 | +) |
| 22 | + |
| 23 | +var _ = g.Describe("ScyllaCluster", func() { |
| 24 | + f := framework.NewFramework("scyllacluster") |
| 25 | + |
| 26 | + g.It("listens only on secure ports", func() { |
| 27 | + ctx, cancel := context.WithTimeout(context.Background(), testTimeout) |
| 28 | + defer cancel() |
| 29 | + |
| 30 | + sc := f.GetDefaultScyllaCluster() |
| 31 | + sc.Spec.Datacenter.Racks[0].Members = 1 |
| 32 | + sc.Spec.ExposeOptions = &scyllav1.ExposeOptions{ |
| 33 | + BroadcastOptions: &scyllav1.NodeBroadcastOptions{ |
| 34 | + Nodes: scyllav1.BroadcastOptions{ |
| 35 | + Type: scyllav1.BroadcastAddressTypePodIP, |
| 36 | + }, |
| 37 | + Clients: scyllav1.BroadcastOptions{ |
| 38 | + Type: scyllav1.BroadcastAddressTypeServiceClusterIP, |
| 39 | + }, |
| 40 | + }, |
| 41 | + } |
| 42 | + sc.Spec.Alternator = &scyllav1.AlternatorSpec{} |
| 43 | + |
| 44 | + framework.By("Creating a ScyllaCluster with 1 member") |
| 45 | + sc, err := f.ScyllaClient().ScyllaV1().ScyllaClusters(f.Namespace()).Create(ctx, sc, metav1.CreateOptions{}) |
| 46 | + o.Expect(err).NotTo(o.HaveOccurred()) |
| 47 | + |
| 48 | + framework.By("Waiting for the ScyllaCluster to rollout (RV=%s)", sc.ResourceVersion) |
| 49 | + waitCtx1, waitCtx1Cancel := utils.ContextForRollout(ctx, sc) |
| 50 | + defer waitCtx1Cancel() |
| 51 | + sc, err = controllerhelpers.WaitForScyllaClusterState(waitCtx1, f.ScyllaClient().ScyllaV1().ScyllaClusters(sc.Namespace), sc.Name, controllerhelpers.WaitForStateOptions{}, utils.IsScyllaClusterRolledOut) |
| 52 | + o.Expect(err).NotTo(o.HaveOccurred()) |
| 53 | + |
| 54 | + scyllaclusterverification.Verify(ctx, f.KubeClient(), f.ScyllaClient(), sc) |
| 55 | + |
| 56 | + serviceName := naming.MemberServiceNameForScyllaCluster(sc.Spec.Datacenter.Racks[0], sc, 0) |
| 57 | + nodeService, err := f.KubeClient().CoreV1().Services(sc.Namespace).Get(ctx, serviceName, metav1.GetOptions{}) |
| 58 | + o.Expect(err).NotTo(o.HaveOccurred()) |
| 59 | + |
| 60 | + nodeServiceIP := nodeService.Spec.ClusterIP |
| 61 | + o.Expect(nodeServiceIP).NotTo(o.BeEmpty()) |
| 62 | + |
| 63 | + nodePod, err := f.KubeClient().CoreV1().Pods(sc.Namespace).Get(ctx, naming.PodNameFromService(nodeService), metav1.GetOptions{}) |
| 64 | + o.Expect(err).NotTo(o.HaveOccurred()) |
| 65 | + |
| 66 | + nodePodIP := nodePod.Status.PodIP |
| 67 | + o.Expect(nodePodIP).NotTo(o.BeEmpty()) |
| 68 | + |
| 69 | + framework.By("Fetching raw network information from /proc/net/tcp{,6}") |
| 70 | + // Because the network stack is shared between containers in the same Pod, it doesn't matter which container we use. |
| 71 | + // We could also create an ephemeral Container in this Pod with an image we need, but the dependency here |
| 72 | + // is minimal (bash + tail) so, as long as one of the images in this Pod has those, using exec is fine and simplifies the test. |
| 73 | + stdout, stderr, err := tools.PodExec( |
| 74 | + f.KubeClient().CoreV1().RESTClient(), |
| 75 | + f.ClientConfig(), |
| 76 | + nodePod.Namespace, |
| 77 | + nodePod.Name, |
| 78 | + "scylla", |
| 79 | + []string{ |
| 80 | + "/usr/bin/bash", |
| 81 | + "-euEo", |
| 82 | + "pipefail", |
| 83 | + "-O", |
| 84 | + "inherit_errexit", |
| 85 | + "-c", |
| 86 | + strings.TrimPrefix(` |
| 87 | +tail -n +2 /proc/net/tcp |
| 88 | +tail -n +2 /proc/net/tcp6 |
| 89 | +`, "\n"), |
| 90 | + }, |
| 91 | + nil, |
| 92 | + ) |
| 93 | + o.Expect(err).NotTo(o.HaveOccurred()) |
| 94 | + o.Expect(stderr).To(o.BeEmpty()) |
| 95 | + o.Expect(stdout).NotTo(o.BeEmpty()) |
| 96 | + |
| 97 | + procNetEntries, err := linuxnetutils.ParseProcNetEntries(stdout) |
| 98 | + o.Expect(err).NotTo(o.HaveOccurred()) |
| 99 | + o.Expect(procNetEntries).NotTo(o.BeEmpty()) |
| 100 | + |
| 101 | + listenProcNetEntries := procNetEntries.FilterListen() |
| 102 | + /* |
| 103 | + * This is a list of allowed ports to be exposed using default configuration. |
| 104 | + * All of these ports should use encryption and force AuthN/AuthZ, unless it is not appropriate |
| 105 | + * or required for the type of data, e.g. /readyz probes. |
| 106 | + * We have some techdebt in this area so this contains some historical ports that don't uphold |
| 107 | + * to this standard. All such entries should have an issue link attached. |
| 108 | + * |
| 109 | + * Note: Some applications bind dedicated IPv4 and IPv6 socket while some reuse the IPv6 socket for IPv4 as well. |
| 110 | + */ |
| 111 | + o.Expect(listenProcNetEntries).To(o.ConsistOf([]linuxnetutils.AddressPort{ |
| 112 | + { |
| 113 | + Address: net.ParseIP("::"), |
| 114 | + Port: 5090, // ScyllaDB Manager agent - metrics (insecure) |
| 115 | + }, |
| 116 | + { |
| 117 | + Address: net.ParseIP("127.0.0.1"), |
| 118 | + Port: 5112, // ScyllaDB Manager agent - debug (insecure) |
| 119 | + }, |
| 120 | + { |
| 121 | + Address: net.ParseIP("0.0.0.0"), |
| 122 | + Port: 7000, // ScyllaDB inter-node (insecure) |
| 123 | + // FIXME: Remove |
| 124 | + // https://github.com/scylladb/scylla-operator/issues/1217 |
| 125 | + }, |
| 126 | + { |
| 127 | + Address: net.ParseIP("0.0.0.0"), |
| 128 | + Port: 8043, // Alternator TLS |
| 129 | + }, |
| 130 | + { |
| 131 | + Address: net.ParseIP("::"), |
| 132 | + Port: 8080, // Scylla Operator probes (insecure, non-sensitive data) |
| 133 | + }, |
| 134 | + { |
| 135 | + Address: net.ParseIP("::"), |
| 136 | + Port: 42081, // ScyllaDB ignition probe |
| 137 | + }, |
| 138 | + { |
| 139 | + Address: net.ParseIP("127.0.0.1"), |
| 140 | + Port: 9001, // supervisord (planned for removal with cont) |
| 141 | + // FIXME: Remove |
| 142 | + // https://github.com/scylladb/scylla-operator/issues/1769 |
| 143 | + }, |
| 144 | + { |
| 145 | + Address: net.ParseIP("::"), |
| 146 | + Port: 9100, // Node exporter - metrics (insecure) |
| 147 | + }, |
| 148 | + { |
| 149 | + Address: net.ParseIP("0.0.0.0"), |
| 150 | + Port: 9042, // CQL (insecure) |
| 151 | + // FIXME: Remove |
| 152 | + // https://github.com/scylladb/scylla-operator/issues/1764 |
| 153 | + }, |
| 154 | + { |
| 155 | + Address: net.ParseIP("0.0.0.0"), |
| 156 | + Port: 9142, // CQL TLS (not AuthZ by default) |
| 157 | + // FIXME: Enforce AuthN+AuthZ by default |
| 158 | + // https://github.com/scylladb/scylla-operator/issues/1770 |
| 159 | + }, |
| 160 | + { |
| 161 | + Address: net.ParseIP("0.0.0.0"), |
| 162 | + Port: 9180, // ScyllaDB - metrics (insecure) |
| 163 | + }, |
| 164 | + { |
| 165 | + Address: net.ParseIP("127.0.0.1"), |
| 166 | + Port: 10000, // ScyllaDB API (insecure and unprotected) |
| 167 | + }, |
| 168 | + { |
| 169 | + Address: net.ParseIP("::"), |
| 170 | + Port: 10001, // ScyllaDB Manager API (insecure but authorized) |
| 171 | + // FIXME: This needs to be replaced with TLS |
| 172 | + // https://github.com/scylladb/scylla-operator/issues/1772 |
| 173 | + }, |
| 174 | + { |
| 175 | + Address: net.ParseIP("0.0.0.0"), |
| 176 | + Port: 19042, // Shard-aware CQL (insecure) |
| 177 | + // FIXME: Remove in favour of port 19142 |
| 178 | + // https://github.com/scylladb/scylla-operator/issues/1764 |
| 179 | + }, |
| 180 | + { |
| 181 | + Address: net.ParseIP("0.0.0.0"), |
| 182 | + Port: 19142, // Shard-aware CQL TLS |
| 183 | + // FIXME: Enforce AuthN+AuthZ by default |
| 184 | + // https://github.com/scylladb/scylla-operator/issues/1770 |
| 185 | + }, |
| 186 | + })) |
| 187 | + }) |
| 188 | +}) |
0 commit comments