mirror of
https://github.com/rancher/k3k.git
synced 2026-08-18 03:46:31 +00:00
Add --tls-sans flag to k3kcli (#925)
* Add --tls-sans flag to k3kcli cluster create * Refine --tls-sans flag description in k3kcli documentation * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Fix TLS SANs handling in cluster creation by using hostname directly * Implement extractHost function and update TLS SAN handling in cluster creation --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -43,6 +43,7 @@ type CreateConfig struct {
|
||||
agentEnvs []string
|
||||
labels []string
|
||||
annotations []string
|
||||
tlsSANs []string
|
||||
persistenceType string
|
||||
storageClassName string
|
||||
storageRequestSize string
|
||||
@@ -130,17 +131,14 @@ func createAction(appCtx *AppContext, config *CreateConfig) func(cmd *cobra.Comm
|
||||
}
|
||||
|
||||
// add Host IP address as an extra TLS-SAN to expose the k3k cluster
|
||||
url, err := url.Parse(appCtx.RestConfig.Host)
|
||||
host, err := extractHost(appCtx.RestConfig.Host, config.kubeconfigServerHost)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
host := strings.Split(url.Host, ":")
|
||||
if config.kubeconfigServerHost != "" {
|
||||
host = []string{config.kubeconfigServerHost}
|
||||
}
|
||||
sans := append([]string{host}, config.tlsSANs...)
|
||||
|
||||
cluster.Spec.TLSSANs = []string{host[0]}
|
||||
cluster.Spec.TLSSANs = uniqueStrings(sans)
|
||||
|
||||
if err := client.Create(ctx, cluster); err != nil {
|
||||
if apierrors.IsAlreadyExists(err) {
|
||||
@@ -482,3 +480,34 @@ func getClusterDetails(cluster *v1beta1.Cluster) (string, error) {
|
||||
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
// extractHost returns the hostname from the given server URL, stripping any
|
||||
// port and correctly handling IPv6 addresses (e.g. "[2001:db8::1]:6443").
|
||||
// If override is non-empty it is returned as-is.
|
||||
func extractHost(serverURL, override string) (string, error) {
|
||||
if override != "" {
|
||||
return override, nil
|
||||
}
|
||||
|
||||
u, err := url.Parse(serverURL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return u.Hostname(), nil
|
||||
}
|
||||
|
||||
// uniqueStrings returns a new slice with duplicates removed, preserving the first occurrence order.
|
||||
func uniqueStrings(ss []string) []string {
|
||||
seen := make(map[string]struct{}, len(ss))
|
||||
result := make([]string, 0, len(ss))
|
||||
|
||||
for _, s := range ss {
|
||||
if _, ok := seen[s]; !ok {
|
||||
seen[s] = struct{}{}
|
||||
result = append(result, s)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ func createFlags(cmd *cobra.Command, cfg *CreateConfig) {
|
||||
cmd.Flags().StringSliceVar(&cfg.agentArgs, "agent-args", []string{}, "agents extra arguments")
|
||||
cmd.Flags().StringSliceVar(&cfg.serverEnvs, "server-envs", []string{}, "servers extra Envs")
|
||||
cmd.Flags().StringSliceVar(&cfg.agentEnvs, "agent-envs", []string{}, "agents extra Envs")
|
||||
cmd.Flags().StringSliceVar(&cfg.tlsSANs, "tls-sans", []string{}, "additional Subject Alternative Names for the cluster server TLS certificate")
|
||||
cmd.Flags().StringArrayVar(&cfg.labels, "labels", []string{}, "Labels to add to the cluster object (e.g. key=value)")
|
||||
cmd.Flags().StringArrayVar(&cfg.annotations, "annotations", []string{}, "Annotations to add to the cluster object (e.g. key=value)")
|
||||
cmd.Flags().StringVar(&cfg.version, "version", "", "k3s version")
|
||||
|
||||
@@ -94,3 +94,52 @@ func Test_printClusterDetails(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_extractHost(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
serverURL string
|
||||
override string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "plain host",
|
||||
serverURL: "https://example.com",
|
||||
want: "example.com",
|
||||
},
|
||||
{
|
||||
name: "host with port",
|
||||
serverURL: "https://example.com:6443",
|
||||
want: "example.com",
|
||||
},
|
||||
{
|
||||
name: "ipv4 with port",
|
||||
serverURL: "https://192.0.2.1:6443",
|
||||
want: "192.0.2.1",
|
||||
},
|
||||
{
|
||||
name: "ipv6 without port",
|
||||
serverURL: "https://[2001:db8::1]",
|
||||
want: "2001:db8::1",
|
||||
},
|
||||
{
|
||||
name: "ipv6 with port",
|
||||
serverURL: "https://[2001:db8::1]:6443",
|
||||
want: "2001:db8::1",
|
||||
},
|
||||
{
|
||||
name: "override wins",
|
||||
serverURL: "https://example.com:6443",
|
||||
override: "custom.host",
|
||||
want: "custom.host",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
host, err := extractHost(tt.serverURL, tt.override)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.want, host)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ k3kcli cluster create [command options] NAME
|
||||
--storage-class-name string storage class name for dynamic persistence type
|
||||
--storage-request-size string storage size for dynamic persistence type
|
||||
--timeout duration The timeout for waiting for the cluster to become ready (e.g., 10s, 5m, 1h). (default 3m0s)
|
||||
--tls-sans strings additional Subject Alternative Names for the cluster server TLS certificate
|
||||
--token string token of the cluster
|
||||
--version string k3s version
|
||||
----
|
||||
|
||||
@@ -36,6 +36,7 @@ k3kcli cluster create [command options] NAME
|
||||
--storage-class-name string storage class name for dynamic persistence type
|
||||
--storage-request-size string storage size for dynamic persistence type
|
||||
--timeout duration The timeout for waiting for the cluster to become ready (e.g., 10s, 5m, 1h). (default 3m0s)
|
||||
--tls-sans strings additional Subject Alternative Names for the cluster server TLS certificate
|
||||
--token string token of the cluster
|
||||
--version string k3s version
|
||||
```
|
||||
|
||||
@@ -113,6 +113,45 @@ var _ = When("using the k3kcli", Label("cli"), func() {
|
||||
Expect(err).To(Not(HaveOccurred()), string(stderr))
|
||||
Expect(stderr).To(ContainSubstring("You can start using the cluster"))
|
||||
})
|
||||
|
||||
It("can create a cluster with multiple --tls-sans values", func() {
|
||||
var (
|
||||
stderr string
|
||||
err error
|
||||
)
|
||||
|
||||
clusterName := "cluster-" + rand.String(5)
|
||||
namespace := fwk3k.CreateNamespace(k8s)
|
||||
clusterNamespace := namespace.Name
|
||||
|
||||
DeferCleanup(func() {
|
||||
fwk3k.DeleteNamespaces(k8s, clusterNamespace)
|
||||
})
|
||||
|
||||
_, stderr, err = K3kcli("cluster", "create",
|
||||
"--namespace", clusterNamespace,
|
||||
"--tls-sans", "extra.example.com",
|
||||
"--tls-sans", "192.0.2.1",
|
||||
"--tls-sans", "host.example.com:6443",
|
||||
"--tls-sans", "2001:db8::1",
|
||||
"--tls-sans", "[2001:db8::1]:6443",
|
||||
clusterName,
|
||||
)
|
||||
Expect(err).To(Not(HaveOccurred()), string(stderr))
|
||||
Expect(stderr).To(ContainSubstring("You can start using the cluster"))
|
||||
|
||||
var cluster v1beta1.Cluster
|
||||
|
||||
err = k8sClient.Get(context.Background(), types.NamespacedName{Name: clusterName, Namespace: clusterNamespace}, &cluster)
|
||||
Expect(err).To(Not(HaveOccurred()))
|
||||
Expect(cluster.Spec.TLSSANs).To(ContainElements(
|
||||
"extra.example.com",
|
||||
"192.0.2.1",
|
||||
"host.example.com:6443",
|
||||
"2001:db8::1",
|
||||
"[2001:db8::1]:6443",
|
||||
))
|
||||
})
|
||||
})
|
||||
|
||||
When("trying the policy commands", func() {
|
||||
|
||||
Reference in New Issue
Block a user