From cb89b725ea46a81b1c89151908ae4c55d37f51e2 Mon Sep 17 00:00:00 2001 From: Gabriel Hernandez Date: Wed, 2 Aug 2023 17:42:01 +0100 Subject: [PATCH] implement fleetctl apply new team with secret (#13062) relates to #12907 implement adding an enroll secret when creating a new team with `fleetctl apply` if none is provided. - [x] Changes file added for user-visible changes in `changes/` or `orbit/changes/`. See [Changes files](https://fleetdm.com/docs/contributing/committing-changes#changes-files) for more information. - [ ] Added/updated tests - [x] Manual QA for all new/changed functionality --- ...issue-12907-add-enroll-secret-for-new-team | 1 + ee/server/service/teams.go | 12 +++++ server/service/integration_enterprise_test.go | 2 +- server/service/teams_test.go | 52 +++++++++++++++++++ 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 changes/issue-12907-add-enroll-secret-for-new-team diff --git a/changes/issue-12907-add-enroll-secret-for-new-team b/changes/issue-12907-add-enroll-secret-for-new-team new file mode 100644 index 0000000000..b5e67d171d --- /dev/null +++ b/changes/issue-12907-add-enroll-secret-for-new-team @@ -0,0 +1 @@ +- add enroll secret for a new team created with `fleetctl apply` if none is provided. diff --git a/ee/server/service/teams.go b/ee/server/service/teams.go index 4d0119ccca..ac7e793896 100644 --- a/ee/server/service/teams.go +++ b/ee/server/service/teams.go @@ -706,6 +706,18 @@ func (svc *Service) ApplyTeamSpecs(ctx context.Context, specs []*fleet.TeamSpec, } if create { + + // create a new team enroll secret if none is provided for a new team. + if len(secrets) == 0 { + secret, err := server.GenerateRandomText(fleet.EnrollSecretDefaultLength) + if err != nil { + return nil, ctxerr.Wrap(ctx, err, "generate enroll secret string") + } + secrets = append(secrets, &fleet.EnrollSecret{ + Secret: secret, + }) + } + team, err := svc.createTeamFromSpec(ctx, spec, appConfig, secrets, applyOpts.DryRun) if err != nil { return nil, ctxerr.Wrap(ctx, err, "creating team from spec") diff --git a/server/service/integration_enterprise_test.go b/server/service/integration_enterprise_test.go index bd46481e55..cde0d77ca1 100644 --- a/server/service/integration_enterprise_test.go +++ b/server/service/integration_enterprise_test.go @@ -355,7 +355,7 @@ func (s *integrationEnterpriseTestSuite) TestTeamSpecs() { appConfig, err := s.ds.AppConfig(context.Background()) require.NoError(t, err) defaultOpts := `{"config": {"options": {"logger_plugin": "tls", "pack_delimiter": "/", "logger_tls_period": 10, "distributed_plugin": "tls", "disable_distributed": false, "logger_tls_endpoint": "/api/osquery/log", "distributed_interval": 10, "distributed_tls_max_attempts": 3}, "decorators": {"load": ["SELECT uuid AS host_uuid FROM system_info;", "SELECT hostname AS hostname FROM system_info;"]}}, "overrides": {}}` - assert.Len(t, team.Secrets, 0) // no secret gets created automatically when creating a team via apply spec + assert.Len(t, team.Secrets, 1) // secret gets created automatically for a new team when none is supplied. require.NotNil(t, team.Config.AgentOptions) require.JSONEq(t, defaultOpts, string(*team.Config.AgentOptions)) require.Equal(t, appConfig.Features, team.Config.Features) diff --git a/server/service/teams_test.go b/server/service/teams_test.go index bb3af518b1..dbba3aa49d 100644 --- a/server/service/teams_test.go +++ b/server/service/teams_test.go @@ -371,6 +371,58 @@ func TestApplyTeamSpecs(t *testing.T) { }) } +// Tests that a new enroll secret is created for new teams when none are provided +func TestApplyTeamSpecEnrollSecretForNewTeams(t *testing.T) { + ds := new(mock.Store) + license := &fleet.LicenseInfo{Tier: fleet.TierPremium, Expiration: time.Now().Add(24 * time.Hour)} + svc, ctx := newTestService(t, ds, nil, nil, &TestServerOpts{License: license, SkipCreateTestUsers: true}) + user := &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)} + ctx = viewer.NewContext(ctx, viewer.Viewer{User: user}) + + ds.TeamByNameFunc = func(ctx context.Context, name string) (*fleet.Team, error) { + return nil, newNotFoundError() + } + + ds.AppConfigFunc = func(ctx context.Context) (*fleet.AppConfig, error) { + return &fleet.AppConfig{}, nil + } + + ds.NewActivityFunc = func(ctx context.Context, user *fleet.User, activity fleet.ActivityDetails) error { + return nil + } + + t.Run("creates enroll secret when not included for a new team spec", func(t *testing.T) { + ds.NewTeamFunc = func(ctx context.Context, team *fleet.Team) (*fleet.Team, error) { + require.Len(t, team.Secrets, 1) + require.NotEmpty(t, team.Secrets[0]) + return &fleet.Team{ID: 1}, nil + } + + _, err := svc.ApplyTeamSpecs(ctx, []*fleet.TeamSpec{{Name: "Foo"}}, fleet.ApplySpecOptions{}) + require.NoError(t, err) + require.True(t, ds.TeamByNameFuncInvoked) + require.True(t, ds.NewTeamFuncInvoked) + }) + + t.Run("does not create enroll secret when one is included for a new team spec", func(t *testing.T) { + enrollSecret := fleet.EnrollSecret{Secret: "test"} + + ds.NewTeamFunc = func(ctx context.Context, team *fleet.Team) (*fleet.Team, error) { + require.Len(t, team.Secrets, 1) + require.Equal(t, enrollSecret.Secret, team.Secrets[0].Secret) + return &fleet.Team{ID: 1}, nil + } + + _, err := svc.ApplyTeamSpecs(ctx, []*fleet.TeamSpec{{Name: "Foo", Secrets: []fleet.EnrollSecret{enrollSecret}}}, fleet.ApplySpecOptions{}) + require.NoError(t, err) + require.True(t, ds.TeamByNameFuncInvoked) + require.True(t, ds.NewTeamFuncInvoked) + }) + + ds.TeamByNameFuncInvoked = false + ds.NewTeamFuncInvoked = false +} + // TestApplyTeamSpecsErrorInTeamByName tests that an error in ds.TeamByName will // result in a proper error returned (instead of the authorization check missing error). func TestApplyTeamSpecsErrorInTeamByName(t *testing.T) {