mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Serviceaccounts: convert selection of apikeys to serviceaccounts (#44154)
* convert selected of apikeys to serviceaccounts * update to use one by one * expose endpoint of service account
This commit is contained in:
parent
7bf25f62e1
commit
9ccc7ec76e
@ -52,6 +52,7 @@ func (api *ServiceAccountsAPI) RegisterAPIEndpoints(
|
||||
serviceAccountsRoute.Get("/:serviceAccountId", auth(middleware.ReqOrgAdmin, accesscontrol.EvalPermission(serviceaccounts.ActionRead, serviceaccounts.ScopeID)), routing.Wrap(api.RetrieveServiceAccount))
|
||||
serviceAccountsRoute.Delete("/:serviceAccountId", auth(middleware.ReqOrgAdmin, accesscontrol.EvalPermission(serviceaccounts.ActionDelete, serviceaccounts.ScopeID)), routing.Wrap(api.DeleteServiceAccount))
|
||||
serviceAccountsRoute.Get("/upgrade", auth(middleware.ReqOrgAdmin, accesscontrol.EvalPermission(serviceaccounts.ActionCreate, serviceaccounts.ScopeID)), routing.Wrap(api.UpgradeServiceAccounts))
|
||||
serviceAccountsRoute.Post("/convert/:keyId", auth(middleware.ReqOrgAdmin, accesscontrol.EvalPermission(serviceaccounts.ActionCreate, serviceaccounts.ScopeID)), routing.Wrap(api.ConvertToServiceAccount))
|
||||
serviceAccountsRoute.Post("/", auth(middleware.ReqOrgAdmin, accesscontrol.EvalPermission(serviceaccounts.ActionCreate, serviceaccounts.ScopeID)), routing.Wrap(api.CreateServiceAccount))
|
||||
serviceAccountsRoute.Get("/:serviceAccountId/tokens", auth(middleware.ReqOrgAdmin, accesscontrol.EvalPermission(serviceaccounts.ActionRead, serviceaccounts.ScopeID)), routing.Wrap(api.ListTokens))
|
||||
})
|
||||
@ -94,6 +95,18 @@ func (api *ServiceAccountsAPI) UpgradeServiceAccounts(ctx *models.ReqContext) re
|
||||
}
|
||||
}
|
||||
|
||||
func (api *ServiceAccountsAPI) ConvertToServiceAccount(ctx *models.ReqContext) response.Response {
|
||||
keyId, err := strconv.ParseInt(web.Params(ctx.Req)[":keyId"], 10, 64)
|
||||
if err != nil {
|
||||
return response.Error(http.StatusBadRequest, "keyId is invalid", err)
|
||||
}
|
||||
if err := api.store.ConvertToServiceAccounts(ctx.Req.Context(), []int64{keyId}); err == nil {
|
||||
return response.Success("service accounts converted")
|
||||
} else {
|
||||
return response.Error(500, "Internal server error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (api *ServiceAccountsAPI) ListTokens(ctx *models.ReqContext) response.Response {
|
||||
saID, err := strconv.ParseInt(web.Params(ctx.Req)[":serviceAccountId"], 10, 64)
|
||||
if err != nil {
|
||||
|
@ -70,24 +70,51 @@ func (s *ServiceAccountsStoreImpl) UpgradeServiceAccounts(ctx context.Context) e
|
||||
s.log.Info("Launching background thread to upgrade API keys to service accounts", "numberKeys", len(basicKeys))
|
||||
go func() {
|
||||
for _, key := range basicKeys {
|
||||
sa, err := s.sqlStore.CreateServiceAccountForApikey(ctx, key.OrgId, key.Name, key.Role)
|
||||
err := s.CreateServiceAccountFromApikey(ctx, key)
|
||||
if err != nil {
|
||||
s.log.Error("Failed to create service account for API key", "err", err, "keyId", key.Id)
|
||||
continue
|
||||
s.log.Error("migating to service accounts failed with error", err)
|
||||
}
|
||||
|
||||
err = s.sqlStore.UpdateApikeyServiceAccount(ctx, key.Id, sa.Id)
|
||||
if err != nil {
|
||||
s.log.Error("Failed to attach new service account to API key", "err", err, "keyId", key.Id, "newServiceAccountId", sa.Id)
|
||||
continue
|
||||
}
|
||||
s.log.Debug("Updated basic api key", "keyId", key.Id, "newServiceAccountId", sa.Id)
|
||||
}
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ServiceAccountsStoreImpl) ConvertToServiceAccounts(ctx context.Context, keys []int64) error {
|
||||
basicKeys := s.sqlStore.GetNonServiceAccountAPIKeys(ctx)
|
||||
if len(basicKeys) == 0 {
|
||||
return nil
|
||||
}
|
||||
if len(basicKeys) != len(keys) {
|
||||
return fmt.Errorf("one of the keys already has a serviceaccount")
|
||||
}
|
||||
for _, key := range basicKeys {
|
||||
if !contains(keys, key.Id) {
|
||||
s.log.Error("convert service accounts stopped for keyId %d as it is not part of the query to convert or already has a service account", key.Id)
|
||||
continue
|
||||
}
|
||||
err := s.CreateServiceAccountFromApikey(ctx, key)
|
||||
if err != nil {
|
||||
s.log.Error("converting to service accounts failed with error", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ServiceAccountsStoreImpl) CreateServiceAccountFromApikey(ctx context.Context, key *models.ApiKey) error {
|
||||
sa, err := s.sqlStore.CreateServiceAccountForApikey(ctx, key.OrgId, key.Name, key.Role)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create service account for API key with error : %w", err)
|
||||
}
|
||||
|
||||
err = s.sqlStore.UpdateApikeyServiceAccount(ctx, key.Id, sa.Id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to attach new service account to API key for keyId: %d and newServiceAccountId: %d with error: %w", key.Id, sa.Id, err)
|
||||
}
|
||||
s.log.Debug("Updated basic api key", "keyId", key.Id, "newServiceAccountId", sa.Id)
|
||||
return nil
|
||||
}
|
||||
|
||||
//nolint:gosimple
|
||||
func (s *ServiceAccountsStoreImpl) ListTokens(ctx context.Context, orgID int64, serviceAccount int64) ([]*models.ApiKey, error) {
|
||||
result := make([]*models.ApiKey, 0)
|
||||
@ -126,3 +153,12 @@ func (s *ServiceAccountsStoreImpl) RetrieveServiceAccount(ctx context.Context, o
|
||||
|
||||
return query.Result[0], err
|
||||
}
|
||||
|
||||
func contains(s []int64, e int64) bool {
|
||||
for _, a := range s {
|
||||
if a == e {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -18,5 +18,6 @@ type Store interface {
|
||||
RetrieveServiceAccount(ctx context.Context, orgID, serviceAccountID int64) (*models.OrgUserDTO, error)
|
||||
DeleteServiceAccount(ctx context.Context, orgID, serviceAccountID int64) error
|
||||
UpgradeServiceAccounts(ctx context.Context) error
|
||||
ConvertToServiceAccounts(ctx context.Context, keys []int64) error
|
||||
ListTokens(ctx context.Context, orgID int64, serviceAccount int64) ([]*models.ApiKey, error)
|
||||
}
|
||||
|
@ -61,6 +61,7 @@ type Calls struct {
|
||||
RetrieveServiceAccount []interface{}
|
||||
DeleteServiceAccount []interface{}
|
||||
UpgradeServiceAccounts []interface{}
|
||||
ConvertServiceAccounts []interface{}
|
||||
ListTokens []interface{}
|
||||
}
|
||||
|
||||
@ -85,6 +86,11 @@ func (s *ServiceAccountsStoreMock) UpgradeServiceAccounts(ctx context.Context) e
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ServiceAccountsStoreMock) ConvertToServiceAccounts(ctx context.Context, keys []int64) error {
|
||||
s.Calls.ConvertServiceAccounts = append(s.Calls.ConvertServiceAccounts, []interface{}{ctx})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ServiceAccountsStoreMock) ListTokens(ctx context.Context, orgID int64, serviceAccount int64) ([]*models.ApiKey, error) {
|
||||
s.Calls.ListTokens = append(s.Calls.ListTokens, []interface{}{ctx, orgID, serviceAccount})
|
||||
return nil, nil
|
||||
|
Loading…
Reference in New Issue
Block a user