2016-11-18 12:14:03 +00:00
|
|
|
/*
|
|
|
|
Copyright 2016 The Kubernetes Authors.
|
|
|
|
|
|
|
|
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 secret
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
|
2017-06-22 17:25:57 +00:00
|
|
|
"k8s.io/api/core/v1"
|
2017-06-23 20:56:37 +00:00
|
|
|
clientset "k8s.io/client-go/kubernetes"
|
2017-02-23 05:35:44 +00:00
|
|
|
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
2016-11-18 12:14:03 +00:00
|
|
|
|
2017-01-06 19:47:43 +00:00
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"k8s.io/apimachinery/pkg/util/sets"
|
2016-11-18 12:14:03 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Manager interface {
|
|
|
|
// Get secret by secret namespace and name.
|
|
|
|
GetSecret(namespace, name string) (*v1.Secret, error)
|
|
|
|
|
2017-01-06 19:47:43 +00:00
|
|
|
// WARNING: Register/UnregisterPod functions should be efficient,
|
|
|
|
// i.e. should not block on network operations.
|
|
|
|
|
2016-11-18 12:14:03 +00:00
|
|
|
// RegisterPod registers all secrets from a given pod.
|
|
|
|
RegisterPod(pod *v1.Pod)
|
|
|
|
|
|
|
|
// UnregisterPod unregisters secrets from a given pod that are not
|
2017-01-06 19:47:43 +00:00
|
|
|
// used by any other registered pod.
|
2016-11-18 12:14:03 +00:00
|
|
|
UnregisterPod(pod *v1.Pod)
|
|
|
|
}
|
|
|
|
|
2018-05-01 17:47:38 +00:00
|
|
|
type objectKey struct {
|
|
|
|
namespace string
|
|
|
|
name string
|
|
|
|
}
|
|
|
|
|
2016-11-18 12:14:03 +00:00
|
|
|
// simpleSecretManager implements SecretManager interfaces with
|
|
|
|
// simple operations to apiserver.
|
|
|
|
type simpleSecretManager struct {
|
|
|
|
kubeClient clientset.Interface
|
|
|
|
}
|
|
|
|
|
2017-01-22 06:30:50 +00:00
|
|
|
func NewSimpleSecretManager(kubeClient clientset.Interface) Manager {
|
|
|
|
return &simpleSecretManager{kubeClient: kubeClient}
|
2016-11-18 12:14:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *simpleSecretManager) GetSecret(namespace, name string) (*v1.Secret, error) {
|
2017-10-25 15:54:32 +00:00
|
|
|
return s.kubeClient.CoreV1().Secrets(namespace).Get(name, metav1.GetOptions{})
|
2016-11-18 12:14:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *simpleSecretManager) RegisterPod(pod *v1.Pod) {
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *simpleSecretManager) UnregisterPod(pod *v1.Pod) {
|
|
|
|
}
|
|
|
|
|
2018-05-01 17:47:38 +00:00
|
|
|
// store is the interface for a secrets cache that
|
|
|
|
// can be used by cacheBasedSecretManager.
|
|
|
|
type store interface {
|
2018-05-09 16:14:50 +00:00
|
|
|
// AddReference adds a reference to the secret to the store.
|
2018-05-01 17:47:38 +00:00
|
|
|
// Note that multiple additions to the store has to be allowed
|
|
|
|
// in the implementations and effectively treated as refcounted.
|
2018-05-09 16:14:50 +00:00
|
|
|
AddReference(namespace, name string)
|
|
|
|
// DeleteReference deletes reference to the secret from the store.
|
2018-05-01 17:47:38 +00:00
|
|
|
// Note that secret should be deleted only when there was a
|
|
|
|
// corresponding Delete call for each of Add calls (effectively
|
|
|
|
// when refcount was reduced to zero).
|
2018-05-09 16:14:50 +00:00
|
|
|
DeleteReference(namespace, name string)
|
2018-05-01 17:47:38 +00:00
|
|
|
// Get a secret from a store.
|
|
|
|
Get(namespace, name string) (*v1.Secret, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// cachingBasedSecretManager keeps a store with secrets necessary
|
|
|
|
// for registered pods. Different implementations of the store
|
|
|
|
// may result in different semantics for freshness of secrets
|
|
|
|
// (e.g. ttl-based implementation vs watch-based implementation).
|
|
|
|
type cacheBasedSecretManager struct {
|
|
|
|
secretStore store
|
2016-11-18 12:14:03 +00:00
|
|
|
|
|
|
|
lock sync.Mutex
|
|
|
|
registeredPods map[objectKey]*v1.Pod
|
|
|
|
}
|
|
|
|
|
2018-05-01 17:47:38 +00:00
|
|
|
func newCacheBasedSecretManager(secretStore store) Manager {
|
|
|
|
return &cacheBasedSecretManager{
|
|
|
|
secretStore: secretStore,
|
2016-11-18 12:14:03 +00:00
|
|
|
registeredPods: make(map[objectKey]*v1.Pod),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-01 17:47:38 +00:00
|
|
|
func (c *cacheBasedSecretManager) GetSecret(namespace, name string) (*v1.Secret, error) {
|
2016-11-18 12:14:03 +00:00
|
|
|
return c.secretStore.Get(namespace, name)
|
|
|
|
}
|
|
|
|
|
|
|
|
func getSecretNames(pod *v1.Pod) sets.String {
|
|
|
|
result := sets.NewString()
|
2017-02-23 05:35:44 +00:00
|
|
|
podutil.VisitPodSecretNames(pod, func(name string) bool {
|
|
|
|
result.Insert(name)
|
|
|
|
return true
|
|
|
|
})
|
2016-11-18 12:14:03 +00:00
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2018-05-01 17:47:38 +00:00
|
|
|
func (c *cacheBasedSecretManager) RegisterPod(pod *v1.Pod) {
|
2017-01-06 19:47:43 +00:00
|
|
|
names := getSecretNames(pod)
|
|
|
|
c.lock.Lock()
|
|
|
|
defer c.lock.Unlock()
|
|
|
|
for name := range names {
|
2018-05-09 16:14:50 +00:00
|
|
|
c.secretStore.AddReference(pod.Namespace, name)
|
2016-11-18 12:14:03 +00:00
|
|
|
}
|
|
|
|
var prev *v1.Pod
|
2017-01-06 19:47:43 +00:00
|
|
|
key := objectKey{namespace: pod.Namespace, name: pod.Name}
|
|
|
|
prev = c.registeredPods[key]
|
|
|
|
c.registeredPods[key] = pod
|
2016-11-18 12:14:03 +00:00
|
|
|
if prev != nil {
|
2017-01-06 19:47:43 +00:00
|
|
|
for name := range getSecretNames(prev) {
|
2017-09-06 19:30:23 +00:00
|
|
|
// On an update, the .Add() call above will have re-incremented the
|
|
|
|
// ref count of any existing secrets, so any secrets that are in both
|
|
|
|
// names and prev need to have their ref counts decremented. Any that
|
|
|
|
// are only in prev need to be completely removed. This unconditional
|
|
|
|
// call takes care of both cases.
|
2018-05-09 16:14:50 +00:00
|
|
|
c.secretStore.DeleteReference(prev.Namespace, name)
|
2016-11-18 12:14:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-01 17:47:38 +00:00
|
|
|
func (c *cacheBasedSecretManager) UnregisterPod(pod *v1.Pod) {
|
2016-11-18 12:14:03 +00:00
|
|
|
var prev *v1.Pod
|
2017-01-06 19:47:43 +00:00
|
|
|
key := objectKey{namespace: pod.Namespace, name: pod.Name}
|
|
|
|
c.lock.Lock()
|
|
|
|
defer c.lock.Unlock()
|
|
|
|
prev = c.registeredPods[key]
|
|
|
|
delete(c.registeredPods, key)
|
2016-11-18 12:14:03 +00:00
|
|
|
if prev != nil {
|
2017-01-06 19:47:43 +00:00
|
|
|
for name := range getSecretNames(prev) {
|
2018-05-09 16:14:50 +00:00
|
|
|
c.secretStore.DeleteReference(prev.Namespace, name)
|
2016-11-18 12:14:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|