-
Notifications
You must be signed in to change notification settings - Fork 2.1k
add self-repair for malformed instance certs #41467
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,238 @@ | ||
| /* | ||
| * Teleport | ||
| * Copyright (C) 2024 Gravitational, Inc. | ||
| * | ||
| * This program is free software: you can redistribute it and/or modify | ||
| * it under the terms of the GNU Affero General Public License as published by | ||
| * the Free Software Foundation, either version 3 of the License, or | ||
| * (at your option) any later version. | ||
| * | ||
| * This program is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| * GNU Affero General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU Affero General Public License | ||
| * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| */ | ||
|
|
||
| package integration | ||
|
|
||
| import ( | ||
| "context" | ||
| "net" | ||
| "os" | ||
| "path/filepath" | ||
| "testing" | ||
| "time" | ||
|
|
||
| "github.com/gravitational/trace" | ||
| "github.com/stretchr/testify/require" | ||
|
|
||
| "github.com/gravitational/teleport" | ||
| "github.com/gravitational/teleport/api/breaker" | ||
| "github.com/gravitational/teleport/api/types" | ||
| "github.com/gravitational/teleport/lib" | ||
| "github.com/gravitational/teleport/lib/auth" | ||
| "github.com/gravitational/teleport/lib/backend" | ||
| "github.com/gravitational/teleport/lib/cloud/imds" | ||
| "github.com/gravitational/teleport/lib/defaults" | ||
| "github.com/gravitational/teleport/lib/service" | ||
| "github.com/gravitational/teleport/lib/service/servicecfg" | ||
| "github.com/gravitational/teleport/lib/services" | ||
| "github.com/gravitational/teleport/lib/utils" | ||
| ) | ||
|
|
||
| // basicDirCopy performs a very simplistic recursive copy from one directory to another. this helper was | ||
| // written specifically for setting up teleport data directories for testing purposes and may not be | ||
| // suitable for other applications. | ||
| func basicDirCopy(src string, dst string) error { | ||
| entries, err := os.ReadDir(src) | ||
| if err != nil { | ||
| return trace.Wrap(err) | ||
| } | ||
|
|
||
| if err := os.MkdirAll(dst, teleport.PrivateDirMode); err != nil { | ||
| return trace.Wrap(err) | ||
| } | ||
|
|
||
| for _, entry := range entries { | ||
| if entry.IsDir() { | ||
| if err := basicDirCopy(filepath.Join(src, entry.Name()), filepath.Join(dst, entry.Name())); err != nil { | ||
| return trace.Wrap(err) | ||
| } | ||
| continue | ||
| } | ||
|
|
||
| data, err := os.ReadFile(filepath.Join(src, entry.Name())) | ||
| if err != nil { | ||
| return trace.Wrap(err) | ||
| } | ||
|
|
||
| if err := os.WriteFile(filepath.Join(dst, entry.Name()), data, teleport.PrivateDirMode); err != nil { | ||
| return trace.Wrap(err) | ||
| } | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func getFreeListenAddr() (string, error) { | ||
| l, err := net.Listen("tcp", "localhost:0") | ||
| if err != nil { | ||
| return "", trace.Wrap(err) | ||
| } | ||
|
|
||
| defer l.Close() | ||
| return l.Addr().String(), nil | ||
| } | ||
|
Comment on lines
80
to
88
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are there any guarantees that returned listen address will still be free after the listener is closed?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ish... binding on |
||
|
|
||
| // TestInstanceCertReissue tests the reissuance of an instance certificate when | ||
| // the instance has malformed system roles using pre-constructed data directories | ||
| // generated by an older teleport version that permitted token mix-and-match. | ||
| func TestInstanceCertReissue(t *testing.T) { | ||
| lib.SetInsecureDevMode(true) | ||
| defer lib.SetInsecureDevMode(false) | ||
|
|
||
| ctx, cancel := context.WithCancel(context.Background()) | ||
| defer cancel() | ||
|
|
||
| // Create temporary directories for the auth and agent data directories. | ||
| authDir, agentDir := t.TempDir(), t.TempDir() | ||
|
|
||
| // Write the instance assets to the temporary directories to set up pre-existing | ||
| // state for our teleport instances to use. | ||
| require.NoError(t, basicDirCopy("testdata/auth", authDir)) | ||
| require.NoError(t, basicDirCopy("testdata/agent", agentDir)) | ||
|
|
||
| proxyAddr, err := getFreeListenAddr() | ||
| require.NoError(t, err) | ||
|
|
||
| authAddr, err := getFreeListenAddr() | ||
| require.NoError(t, err) | ||
|
|
||
| authCfg := servicecfg.MakeDefaultConfig() | ||
| authCfg.Version = defaults.TeleportConfigVersionV3 | ||
| authCfg.DataDir = authDir | ||
| require.NoError(t, authCfg.SetAuthServerAddresses([]utils.NetAddr{ | ||
| { | ||
| AddrNetwork: "tcp", | ||
| Addr: authAddr, | ||
| }, | ||
| })) | ||
| authCfg.Auth.Enabled = true | ||
| // ensure auth server is using the pre-constructed sqlite db | ||
| authCfg.Auth.StorageConfig.Params = backend.Params{defaults.BackendPath: filepath.Join(authDir, defaults.BackendDir)} | ||
| authCfg.Auth.ClusterName, err = services.NewClusterNameWithRandomID(types.ClusterNameSpecV2{ | ||
| ClusterName: "auth-server", | ||
| }) | ||
| require.NoError(t, err) | ||
| authCfg.Auth.ListenAddr.Addr = authAddr | ||
| authCfg.Auth.NetworkingConfig.SetProxyListenerMode(types.ProxyListenerMode_Multiplex) | ||
|
|
||
| authCfg.Proxy.Enabled = true | ||
| authCfg.Proxy.DisableWebInterface = true | ||
| authCfg.Proxy.WebAddr.Addr = proxyAddr | ||
|
|
||
| authCfg.SSH.Enabled = true | ||
| authCfg.SSH.Addr.Addr = "localhost:0" | ||
| authCfg.CircuitBreakerConfig = breaker.NoopBreakerConfig() | ||
| authCfg.Log = utils.NewLoggerForTests() | ||
| authCfg.InstanceMetadataClient = imds.NewDisabledIMDSClient() | ||
|
|
||
| authRunErrCh := make(chan error, 1) | ||
| authIdentitiesCh := make(chan *auth.Identity, 2) | ||
| go func() { | ||
| authRunErrCh <- service.Run(ctx, *authCfg, func(cfg *servicecfg.Config) (service.Process, error) { | ||
| proc, err := service.NewTeleport(cfg) | ||
| if err != nil { | ||
| return nil, trace.Wrap(err) | ||
| } | ||
|
|
||
| identity, err := proc.GetIdentity(types.RoleInstance) | ||
| if err != nil { | ||
| proc.Close() | ||
| return nil, trace.Wrap(err) | ||
| } | ||
|
|
||
| select { | ||
| case authIdentitiesCh <- identity: | ||
| default: | ||
| } | ||
|
|
||
| return proc, nil | ||
| }) | ||
| }() | ||
|
|
||
| timeout := time.After(time.Second * 30) | ||
| select { | ||
| case <-timeout: | ||
| t.Fatal("timed out waiting for first auth identity") | ||
| case identity := <-authIdentitiesCh: | ||
| require.ElementsMatch(t, []string{string(types.RoleAuth), string(types.RoleProxy)}, identity.SystemRoles) | ||
| } | ||
|
|
||
| select { | ||
| case <-timeout: | ||
| t.Fatal("timed out waiting for second auth identity") | ||
| case identity := <-authIdentitiesCh: | ||
| require.ElementsMatch(t, []string{string(types.RoleAuth), string(types.RoleProxy), string(types.RoleNode)}, identity.SystemRoles) | ||
| } | ||
|
|
||
| agentCfg := servicecfg.MakeDefaultConfig() | ||
| agentCfg.Version = defaults.TeleportConfigVersionV3 | ||
| agentCfg.DataDir = agentDir | ||
| agentCfg.ProxyServer = utils.NetAddr{ | ||
| AddrNetwork: "tcp", | ||
| Addr: proxyAddr, | ||
| } | ||
|
|
||
| agentCfg.Auth.Enabled = false | ||
| agentCfg.Proxy.Enabled = false | ||
| agentCfg.SSH.Enabled = true | ||
|
|
||
| agentCfg.WindowsDesktop.Enabled = true | ||
| agentCfg.CircuitBreakerConfig = breaker.NoopBreakerConfig() | ||
| agentCfg.Log = utils.NewLoggerForTests() | ||
| agentCfg.MaxRetryPeriod = time.Second | ||
| agentCfg.InstanceMetadataClient = imds.NewDisabledIMDSClient() | ||
|
|
||
| agentRunErrCh := make(chan error, 1) | ||
| agentIdentitiesCh := make(chan *auth.Identity, 2) | ||
| go func() { | ||
| agentRunErrCh <- service.Run(ctx, *agentCfg, func(cfg *servicecfg.Config) (service.Process, error) { | ||
| proc, err := service.NewTeleport(cfg) | ||
| if err != nil { | ||
| return nil, trace.Wrap(err) | ||
| } | ||
|
|
||
| identity, err := proc.GetIdentity(types.RoleInstance) | ||
| if err != nil { | ||
| proc.Close() | ||
| return nil, trace.Wrap(err) | ||
| } | ||
|
|
||
| select { | ||
| case agentIdentitiesCh <- identity: | ||
| default: | ||
| } | ||
|
|
||
| return proc, nil | ||
| }) | ||
| }() | ||
|
|
||
| timeout = time.After(time.Second * 30) | ||
| select { | ||
| case <-timeout: | ||
| t.Fatal("timed out waiting for first agent identity") | ||
| case identity := <-agentIdentitiesCh: | ||
| require.ElementsMatch(t, []string{string(types.RoleNode)}, identity.SystemRoles) | ||
| } | ||
|
|
||
| select { | ||
| case <-timeout: | ||
| t.Fatal("timed out waiting for second agent identity") | ||
| case identity := <-agentIdentitiesCh: | ||
| require.ElementsMatch(t, []string{string(types.RoleNode), string(types.RoleWindowsDesktop)}, identity.SystemRoles) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| 4b60753c-a4c4-435a-8045-b77faabb41d7 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| 1feff6fc-865b-47c1-8a5d-f10e1811c30e |
Uh oh!
There was an error while loading. Please reload this page.