-
Notifications
You must be signed in to change notification settings - Fork 9
feat: add admin-console reset-tls and update-tls commands #3300
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add admin-console reset-tls and update-tls commands #3300
Conversation
Add a new CLI subcommand to securely update Admin Console TLS certificates without using the acceptAnonymousUploads workflow which exposes a security vulnerability. Usage: <installer> admin-console update-tls --tls-cert <path> --tls-key <path> [--hostname <hostname>] The command reads and validates the certificate/key pair, then updates the kotsadm-tls secret. No pod restart is needed as pods using this secret are expected to watch for changes and reload automatically. Optionally accepts --hostname flag for display URL (not TLS validation). Closes: sc-131995 Signed-off-by: Evans Mungai <[email protected]>
|
This PR has been released (on staging) and is available for download with a embedded-cluster-smoke-test-staging-app license ID. Online Installer: Airgap Installer (may take a few minutes before the airgap bundle is built): Happy debugging! |
Signed-off-by: Evans Mungai <[email protected]>
Signed-off-by: Evans Mungai <[email protected]>
| cmd := &cobra.Command{ | ||
| Use: "update-tls", | ||
| Short: fmt.Sprintf("Update the TLS certificate and key for the %s Admin Console", name), | ||
| Long: fmt.Sprintf(`Update the TLS certificate and key used by the %s Admin Console. | ||
|
|
||
| This command updates the kotsadm-tls secret, or creates it if it does not exist. | ||
| Pods using this secret are expected to watch for changes and automatically reload | ||
| the TLS configuration. This provides a secure alternative to the acceptAnonymousUploads | ||
| workflow. | ||
|
|
||
| The --hostname flag is optional and only affects the display URL shown | ||
| to users. It does not affect TLS certificate validation.`, name), | ||
| PreRunE: func(cmd *cobra.Command, args []string) error { | ||
| if !dryrun.Enabled() && os.Getuid() != 0 { | ||
| return fmt.Errorf("update-tls command must be run as root") | ||
| } | ||
| return nil | ||
| }, | ||
| RunE: func(cmd *cobra.Command, args []string) error { | ||
| return runUpdateTLS(cmd.Context(), tlsCertPath, tlsKeyPath, hostname) | ||
| }, | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pinging @ajp-io for a 👀 of the copy here.
| secret = &corev1.Secret{ | ||
| ObjectMeta: metav1.ObjectMeta{ | ||
| Name: kotsadmTLSSecretName, | ||
| Namespace: namespace, | ||
| Labels: adminconsole.GetKotsadmLabels(), | ||
| Annotations: adminconsole.GetTLSSecretAnnotations(), | ||
| }, | ||
| Type: corev1.SecretTypeTLS, | ||
| Data: map[string][]byte{ | ||
| "tls.crt": certBytes, | ||
| "tls.key": keyBytes, | ||
| }, | ||
| } | ||
| if hostname != "" { | ||
| secret.StringData = map[string]string{"hostname": hostname} | ||
| } | ||
| if err := kcli.Create(ctx, secret); err != nil { | ||
| return fmt.Errorf("creating kotsadm-tls secret: %w", err) | ||
| } | ||
| return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about having methods within the adminconsole package that handle creating the secret object (the actual corev1.Secret not the actual kcli.Create albeit that's just an extra step I guess) and also return the name of the kotsadm-tls secret? This means that if/whenever we change any of the aspects around the secret creation (e.g. add labels, change its name, etc.) we don't need to run around in multiple places in the code, everything is scoped to a single place:
embedded-cluster/pkg/addons/adminconsole/install.go
Lines 224 to 249 in 138ce52
secret := &corev1.Secret{ TypeMeta: metav1.TypeMeta{ Kind: "Secret", APIVersion: "v1", }, ObjectMeta: metav1.ObjectMeta{ Name: "kotsadm-tls", Namespace: a.Namespace(), Labels: map[string]string{ "kots.io/kotsadm": "true", "replicated.com/disaster-recovery": "infra", "replicated.com/disaster-recovery-chart": "admin-console", }, Annotations: map[string]string{ "acceptAnonymousUploads": "0", }, }, Type: "kubernetes.io/tls", Data: map[string][]byte{ "tls.crt": a.TLSCertBytes, "tls.key": a.TLSKeyBytes, }, StringData: map[string]string{ "hostname": a.Hostname, }, }
A recent example of something similar I've tried to do:
The general idea being that external components shouldn't need to worry about the particular structure of the secret object, its name, namespace, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call. I'll make that change
Signed-off-by: Evans Mungai <[email protected]>
Co-authored-by: Alex Parker <[email protected]>
| assert.Contains(t, cmd.Short, "Update the TLS certificate") | ||
| assert.Contains(t, cmd.Long, "kotsadm-tls secret") | ||
| assert.Contains(t, cmd.Long, "creates it if it does not exist") | ||
| assert.Contains(t, cmd.Long, "watch for changes") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Test assertions check for text not in command Long
The test TestAdminConsoleUpdateTLSCmd asserts that cmd.Long contains "kotsadm-tls secret", "creates it if it does not exist", and "watch for changes", but the actual Long string defined in AdminConsoleUpdateTLSCmd doesn't contain any of these phrases. The Long description only mentions the hostname flag behavior. These test assertions will fail.
Additional Locations (1)
Signed-off-by: Evans Mungai <[email protected]>
Signed-off-by: Evans Mungai <[email protected]>
Add a new CLI subcommand to regenerate the Admin Console TLS certificate with a fresh self-signed certificate. Usage: <installer> admin-console reset-tls The command generates a new self-signed certificate using tlsutils.GenerateCertificate with all valid host IP addresses as SANs, then updates the kotsadm-tls secret. Useful for certificate expiry or when host IP addresses have changed. Signed-off-by: Evans Mungai <[email protected]>
Signed-off-by: Evans Mungai <[email protected]>
JGAntunes
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small comment on the tests. IMO I don't know how worthwhile is to validate the cmd config, other than that LGTM 👍 thanks! Love the secret creation cleanup.
| func TestAdminConsoleResetTLSCmd(t *testing.T) { | ||
| ctx := context.Background() | ||
| cmd := AdminConsoleResetTLSCmd(ctx, "Test App") | ||
|
|
||
| assert.Equal(t, "reset-tls", cmd.Use) | ||
| assert.Contains(t, cmd.Short, "Reset the TLS certificate") | ||
| assert.Contains(t, cmd.Short, "self-signed") | ||
| assert.Contains(t, cmd.Long, "self-signed TLS certificate") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know how worthwhile this test is since we're mostly asserting on the cmd configuration
| func TestAdminConsoleUpdateTLSCmd(t *testing.T) { | ||
| ctx := context.Background() | ||
| cmd := AdminConsoleUpdateTLSCmd(ctx, "Test App") | ||
|
|
||
| assert.Equal(t, "update-tls", cmd.Use) | ||
| assert.Contains(t, cmd.Short, "Update the TLS certificate") | ||
| assert.Contains(t, cmd.Long, "Update the TLS certificate and key") | ||
| assert.Contains(t, cmd.Long, "--hostname flag is optional") | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above.
Signed-off-by: Evans Mungai <[email protected]>
|
@ajp-io all changes asked for have been addressed |
What this PR does / why we need it:
Add a new CLI subcommand to securely update Admin Console TLS certificates without using the acceptAnonymousUploads workflow which exposes a security vulnerability.
Usage:
<installer> admin-console update-tls --tls-cert <path> --tls-key <path> [--hostname <hostname>]The command reads and validates the certificate/key pair, then updates the kotsadm-tls secret. No pod restart is needed as pods using this secret are expected to watch for changes and reload automatically.
Optionally accepts
--hostnameflag for display URL (not TLS validation).Which issue(s) this PR fixes:
https://app.shortcut.com/replicated/story/131995/add-cli-subcommand-to-update-admin-console-tls-cert-and-key
Does this PR require a test?
Yes. Automated tests and manual tests
Does this PR require a release note?
Does this PR require documentation?
replicatedhq/replicated-docs#3708