mirror of
https://github.com/gravitational/teleport.git
synced 2026-10-31 20:39:37 +08:00
118 lines
4.0 KiB
Go
118 lines
4.0 KiB
Go
//go:build !windows
|
|
// +build !windows
|
|
|
|
/*
|
|
Copyright 2019 Gravitational, Inc.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package auth
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/gravitational/trace"
|
|
|
|
"github.com/gravitational/teleport/lib/backend"
|
|
"github.com/gravitational/teleport/lib/backend/kubernetes"
|
|
"github.com/gravitational/teleport/lib/backend/lite"
|
|
)
|
|
|
|
// NewProcessStorage returns a new instance of the process storage.
|
|
func NewProcessStorage(ctx context.Context, path string) (*ProcessStorage, error) {
|
|
if path == "" {
|
|
return nil, trace.BadParameter("missing parameter path")
|
|
}
|
|
|
|
litebk, err := lite.NewWithConfig(ctx, lite.Config{
|
|
Path: path,
|
|
EventsOff: true,
|
|
Sync: lite.SyncFull,
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, trace.Wrap(err)
|
|
}
|
|
|
|
// identityStorage holds the storage backend for identity and state.
|
|
// if the agent is running in Kubernetes it's replaced by kubernetes secret storage
|
|
var identityStorage stateBackend = litebk
|
|
|
|
// if running in a K8S cluster and required env vars are available
|
|
// the agent will automatically switch state storage from local
|
|
// sqlite into a Kubernetes Secret.
|
|
if kubernetes.InKubeCluster() {
|
|
kubeStorage, err := kubernetes.New()
|
|
if err != nil {
|
|
return nil, trace.Wrap(err)
|
|
}
|
|
|
|
// if secret does not exist but Statefulset had local storage with identities,
|
|
// the agent reads them from SQLite and dumps into Kubernetes Secret.
|
|
// TODO(tigrato): remove this once the compatibility layer between local
|
|
// storage and Kube secret storage is no longer required!
|
|
// DELETE IN: 12.0.0
|
|
if !kubeStorage.Exists(ctx) {
|
|
if err := copyLocalStorageIntoKubernetes(ctx, kubeStorage, litebk); err != nil {
|
|
return nil, trace.Wrap(err)
|
|
}
|
|
}
|
|
|
|
identityStorage = kubeStorage
|
|
}
|
|
|
|
return &ProcessStorage{BackendStorage: litebk, stateStorage: identityStorage}, nil
|
|
}
|
|
|
|
// copyLocalStorageIntoKubernetes reads every `identity` and `state` keys from local storage
|
|
// and copies them into Kubernetes Secret. This code is executed only when the agent starts and the
|
|
// secret was not yet created in K8S. Subsequent restarts of the agent won't execute this code since the
|
|
// secret already exists in K8S
|
|
// TODO(tigrato): remove this once the compatibility layer between local storage and
|
|
// Kube secret storage is no longer required!
|
|
func copyLocalStorageIntoKubernetes(ctx context.Context, k8sStorage stateBackend, litebk *lite.Backend) error {
|
|
// read keys starting with `/ids`, e.g. `/ids/{role}/{current,replacement}`
|
|
idsStorage := readPrefixedKeysFromLocalStorage(ctx, litebk, idsPrefix)
|
|
|
|
// read keys starting with `/states` `/states/{role}/state`
|
|
stateStorage := readPrefixedKeysFromLocalStorage(ctx, litebk, statesPrefix)
|
|
|
|
// if no keys were found, this is a fresh start.
|
|
if len(idsStorage) == 0 && len(stateStorage) == 0 {
|
|
return nil
|
|
}
|
|
|
|
// store keys in K8S Secret
|
|
return trace.Wrap(k8sStorage.PutRange(ctx, append(idsStorage, stateStorage...)))
|
|
}
|
|
|
|
// readPrefixedKeysFromLocalStorage reads every key from local storage whose key starts with `prefix`.
|
|
// If no values were found or an error is returned from SQLite backend, it ignores any error and returns empty items.
|
|
// TODO(tigrato): remove this once the compatibility layer between local storage and Kube secret storage is no longer required!
|
|
func readPrefixedKeysFromLocalStorage(ctx context.Context, litebk *lite.Backend, prefix string) (items []backend.Item) {
|
|
results, err := litebk.GetRange(
|
|
ctx,
|
|
backend.Key(prefix),
|
|
backend.RangeEnd(
|
|
backend.Key(prefix),
|
|
),
|
|
backend.NoLimit,
|
|
)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
return results.Items
|
|
}
|