Remove cluster resetsatoken subcommand

This command is outdated and no longer needed, according to the
design call it should be removed.

Change-Id: I7c96fdd8cbc21c56ad9d0d6291ea9b6c6626735d
Signed-off-by: Ruslan Aliev <raliev@mirantis.com>
Relates-To: #588
This commit is contained in:
Ruslan Aliev 2021-06-24 10:58:45 -05:00
parent 7a89572149
commit ada5d6f131
16 changed files with 4 additions and 711 deletions

View File

@ -17,7 +17,6 @@ package cluster
import (
"github.com/spf13/cobra"
"opendev.org/airship/airshipctl/cmd/cluster/resetsatoken"
"opendev.org/airship/airshipctl/pkg/config"
)
@ -38,7 +37,6 @@ func NewClusterCommand(cfgFactory config.Factory) *cobra.Command {
}
clusterRootCmd.AddCommand(NewStatusCommand(cfgFactory))
clusterRootCmd.AddCommand(resetsatoken.NewResetCommand(cfgFactory))
clusterRootCmd.AddCommand(NewGetKubeconfigCommand(cfgFactory))
clusterRootCmd.AddCommand(NewListCommand(cfgFactory))

View File

@ -1,76 +0,0 @@
/*
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
https://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 resetsatoken
import (
"github.com/spf13/cobra"
"opendev.org/airship/airshipctl/pkg/cluster/resetsatoken"
"opendev.org/airship/airshipctl/pkg/config"
"opendev.org/airship/airshipctl/pkg/log"
)
const (
resetLong = `
Reset/rotate the Service Account(SA) tokens and additionally restart the corresponding pods to get the latest
token data reflected in the pod spec.
Secret-namespace is a mandatory flag and secret-name is optional. If a secret-name is not specified, all of the SA
tokens in the specified namespace are rotated, else only the specified secret-name.
`
resetExample = `
To rotate a particular SA token
# airshipctl cluster rotate-sa-token -n cert-manager -s cert-manager-token-vvn9p
To rotate all the SA tokens in cert-manager namespace
# airshipctl cluster rotate-sa-token -n cert-manager
`
)
// NewResetCommand creates a new command for generating secret information
func NewResetCommand(cfgFactory config.Factory) *cobra.Command {
r := &resetsatoken.ResetCommand{
Options: resetsatoken.ResetFlags{},
CfgFactory: cfgFactory,
}
resetCmd := &cobra.Command{
Use: "rotate-sa-token",
Short: "Airshipctl command to rotate tokens of Service Account(s)",
Long: resetLong[1:],
Example: resetExample,
RunE: func(cmd *cobra.Command, args []string) error {
return r.RunE()
},
}
resetCmd.Flags().StringVarP(&r.Options.Namespace, "secret-namespace", "n", "",
"namespace of the Service Account Token")
resetCmd.Flags().StringVarP(&r.Options.SecretName, "secret-name", "s", "",
"name of the secret containing Service Account Token")
resetCmd.Flags().StringVar(&r.Options.Kubeconfig, "kubeconfig", "",
"path to kubeconfig associated with cluster being managed")
err := resetCmd.MarkFlagRequired("secret-namespace")
if err != nil {
log.Fatal(err)
}
err = resetCmd.MarkFlagRequired("kubeconfig")
if err != nil {
log.Fatalf("marking kubeconfig flag required failed: %v", err)
}
return resetCmd
}

View File

@ -1,36 +0,0 @@
/*
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
https://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 resetsatoken_test
import (
"testing"
"opendev.org/airship/airshipctl/cmd/cluster/resetsatoken"
"opendev.org/airship/airshipctl/testutil"
)
func TestResetToken(t *testing.T) {
cmdTests := []*testutil.CmdTest{
{
Name: "reset-with-help",
CmdLine: "--help",
Cmd: resetsatoken.NewResetCommand(nil),
},
}
for _, tt := range cmdTests {
testutil.RunTest(t, tt)
}
}

View File

@ -1,23 +0,0 @@
Reset/rotate the Service Account(SA) tokens and additionally restart the corresponding pods to get the latest
token data reflected in the pod spec.
Secret-namespace is a mandatory flag and secret-name is optional. If a secret-name is not specified, all of the SA
tokens in the specified namespace are rotated, else only the specified secret-name.
Usage:
rotate-sa-token [flags]
Examples:
To rotate a particular SA token
# airshipctl cluster rotate-sa-token -n cert-manager -s cert-manager-token-vvn9p
To rotate all the SA tokens in cert-manager namespace
# airshipctl cluster rotate-sa-token -n cert-manager
Flags:
-h, --help help for rotate-sa-token
--kubeconfig string path to kubeconfig associated with cluster being managed
-s, --secret-name string name of the secret containing Service Account Token
-n, --secret-namespace string namespace of the Service Account Token

View File

@ -5,11 +5,10 @@ Usage:
cluster [command]
Available Commands:
get-kubeconfig Airshipctl command to retrieve kubeconfig for a desired cluster
help Help about any command
list Airshipctl command to get and list defined clusters
rotate-sa-token Airshipctl command to rotate tokens of Service Account(s)
status Retrieve statuses of deployed cluster components
get-kubeconfig Airshipctl command to retrieve kubeconfig for a desired cluster
help Help about any command
list Airshipctl command to get and list defined clusters
status Retrieve statuses of deployed cluster components
Flags:
-h, --help help for cluster

View File

@ -34,6 +34,5 @@ SEE ALSO
* :ref:`airshipctl <airshipctl>` - A unified command line tool for management of end-to-end kubernetes cluster deployment on cloud infrastructure environments.
* :ref:`airshipctl cluster get-kubeconfig <airshipctl_cluster_get-kubeconfig>` - Airshipctl command to retrieve kubeconfig for a desired cluster
* :ref:`airshipctl cluster list <airshipctl_cluster_list>` - Airshipctl command to get and list defined clusters
* :ref:`airshipctl cluster rotate-sa-token <airshipctl_cluster_rotate-sa-token>` - Airshipctl command to rotate tokens of Service Account(s)
* :ref:`airshipctl cluster status <airshipctl_cluster_status>` - Retrieve statuses of deployed cluster components

View File

@ -8,5 +8,4 @@ cluster
airshipctl_cluster
airshipctl_cluster_get-kubeconfig
airshipctl_cluster_list
airshipctl_cluster_rotate-sa-token
airshipctl_cluster_status

View File

@ -1,60 +0,0 @@
/*
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
https://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 resetsatoken
import (
"opendev.org/airship/airshipctl/pkg/config"
"opendev.org/airship/airshipctl/pkg/k8s/client"
"opendev.org/airship/airshipctl/pkg/log"
)
// ResetFlags flags for reset command
type ResetFlags struct {
Namespace string
SecretName string
Kubeconfig string
}
// ResetCommand for reset command
type ResetCommand struct {
Options ResetFlags
CfgFactory config.Factory
}
// RunE implements the functionality for resetsatoken
func (c *ResetCommand) RunE() error {
airshipconfig, err := c.CfgFactory()
if err != nil {
return err
}
factory := client.DefaultClient
kclient, err := factory(airshipconfig.LoadedConfigPath(), c.Options.Kubeconfig)
if err != nil {
return err
}
manager, err := NewTokenManager(kclient.ClientSet())
if err != nil {
return err
}
log.Printf("Starting Token Rotation")
err = manager.RotateToken(c.Options.Namespace, c.Options.SecretName)
if err != nil {
return ErrRotateTokenFail{Err: err.Error()}
}
return nil
}

View File

@ -1,85 +0,0 @@
/*
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
https://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 resetsatoken_test
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"opendev.org/airship/airshipctl/pkg/cluster/resetsatoken"
"opendev.org/airship/airshipctl/pkg/config"
"opendev.org/airship/airshipctl/pkg/k8s/client"
"opendev.org/airship/airshipctl/pkg/k8s/client/fake"
)
func TestRunE(t *testing.T) {
airshipConfigPath := "testdata/airshipconfig.yaml"
kubeConfigPath := "testdata/kubeconfig.yaml"
tests := []struct {
testCaseName string
testErr string
resetFlags resetsatoken.ResetFlags
cfgFactory config.Factory
}{
{
testCaseName: "invalid config factory",
cfgFactory: func() (*config.Config, error) {
return nil, fmt.Errorf("test config error")
},
resetFlags: resetsatoken.ResetFlags{},
testErr: "test config error",
},
{
testCaseName: "valid config factory",
cfgFactory: config.CreateFactory(&airshipConfigPath),
resetFlags: resetsatoken.ResetFlags{
SecretName: "test-secret",
Namespace: "test-namespace",
},
testErr: "",
},
}
for _, tt := range tests {
t.Run(tt.testCaseName, func(t *testing.T) {
command := resetsatoken.ResetCommand{
Options: tt.resetFlags,
CfgFactory: tt.cfgFactory,
}
err := command.RunE()
if tt.testErr != "" {
assert.Contains(t, err.Error(), tt.testErr)
} else {
fakeConfig, err := command.CfgFactory()
assert.NoError(t, err)
factory := client.DefaultClient
_, err = factory(fakeConfig.LoadedConfigPath(), kubeConfigPath)
assert.NoError(t, err)
fakeClient := fake.NewClient()
assert.NotEmpty(t, fakeClient)
clientset := fakeClient.ClientSet()
fakeManager, err := resetsatoken.NewTokenManager(clientset)
assert.NoError(t, err)
err = fakeManager.RotateToken(command.Options.Namespace, command.Options.SecretName)
assert.Error(t, err)
}
})
}
}

View File

@ -1,46 +0,0 @@
/*
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
https://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 resetsatoken
import (
"fmt"
)
// ErrNoSATokenFound is returned if there are no SA tokens found in the provided namespace
type ErrNoSATokenFound struct {
namespace string
}
// ErrNotSAToken is returned if the user input is not an SA token
type ErrNotSAToken struct {
secretName string
}
// ErrRotateTokenFail is called when there is a failure in rotating the SA token
type ErrRotateTokenFail struct {
Err string
}
func (e ErrNoSATokenFound) Error() string {
return fmt.Sprintf("no service account tokens found in namespace %s", e.namespace)
}
func (e ErrNotSAToken) Error() string {
return fmt.Sprintf("%s is not a Service Account Token", e.secretName)
}
func (e ErrRotateTokenFail) Error() string {
return fmt.Sprintf("failed to rotate token: %s", e.Err)
}

View File

@ -1,139 +0,0 @@
/*
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
https://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 resetsatoken
import (
"fmt"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"opendev.org/airship/airshipctl/pkg/log"
)
const (
replicaSetKind = "ReplicaSet"
)
// TokenManager manages service account rotation
type TokenManager struct {
kclient kubernetes.Interface
}
// NewTokenManager returns an instance of a TokenManager
func NewTokenManager(kclient kubernetes.Interface) (*TokenManager, error) {
return &TokenManager{
kclient: kclient,
}, nil
}
// RotateToken - rotates token > 1. Deletes the secret and 2. Deletes its pod
// Deleting the SA Secret recreates a new secret with a new token information
// However, the pods referencing to the old secret needs to be refreshed
// manually and hence deleting the pod to allow it to get recreated with new
// secret reference
func (manager TokenManager) RotateToken(ns string, secretName string) error {
if secretName == "" {
return manager.rotateAllTokens(ns)
}
return manager.rotateSingleToken(ns, secretName)
}
// deleteSecret- deletes the secret
func (manager TokenManager) deleteSecret(secretName string, ns string) error {
return manager.kclient.CoreV1().Secrets(ns).Delete(secretName, &metav1.DeleteOptions{})
}
// deletePod - identifies the secret relationship with pods and deletes corresponding pods
// if its part of replicaset
func (manager TokenManager) deletePod(secretName string, ns string) error {
pods, err := manager.kclient.CoreV1().Pods(ns).List(metav1.ListOptions{})
if err != nil {
return err
}
for _, pod := range pods.Items {
for _, volume := range pod.Spec.Volumes {
if volume.Name == secretName {
if manager.isReplicaSet(pod.OwnerReferences) {
log.Printf("Deleting pod - %s in %s", pod.Name, ns)
if deleteErr := manager.kclient.CoreV1().Pods(ns).Delete(pod.Name,
&metav1.DeleteOptions{}); deleteErr != nil {
log.Printf("Failed to delete pod: %v", err.Error())
}
}
}
}
}
return nil
}
// rotateAllTokens rotates all the tokens in the given namespace
func (manager TokenManager) rotateAllTokens(ns string) error {
tokenTypeFieldSelector := fmt.Sprintf("type=%s", corev1.SecretTypeServiceAccountToken)
listOptions := metav1.ListOptions{FieldSelector: tokenTypeFieldSelector}
secrets, err := manager.kclient.CoreV1().Secrets(ns).List(listOptions)
if err != nil {
return err
}
if len(secrets.Items) == 0 {
return ErrNoSATokenFound{namespace: ns}
}
for _, secret := range secrets.Items {
err := manager.rotate(secret.Name, secret.Namespace)
if err != nil {
return err
}
}
return nil
}
// rotateSingleToken rotates a given token in the given ns
func (manager TokenManager) rotateSingleToken(ns string, secretName string) error {
secret, err := manager.kclient.CoreV1().Secrets(ns).Get(secretName, metav1.GetOptions{})
if err != nil {
return err
}
if secret.Type != corev1.SecretTypeServiceAccountToken {
return ErrNotSAToken{secretName: secretName}
}
return manager.rotate(secretName, ns)
}
// rotate performs delete action for secrets and its pods
func (manager TokenManager) rotate(secretName string, secretNamespace string) error {
log.Printf("Rotating token - %s in %s", secretName, secretNamespace)
err := manager.deleteSecret(secretName, secretNamespace)
if err != nil {
return err
}
return manager.deletePod(secretName, secretNamespace)
}
// isReplicaSet checks if the pod is controlled by a ReplicaSet making it safe to delete
func (manager TokenManager) isReplicaSet(ownerReferences []metav1.OwnerReference) bool {
for _, ownerRef := range ownerReferences {
if ownerRef.Kind == replicaSetKind {
return true
}
}
return false
}

View File

@ -1,166 +0,0 @@
/*
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
https://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 resetsatoken_test
import (
"io/ioutil"
"testing"
"github.com/stretchr/testify/assert"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/yaml"
kfake "k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/kubernetes/scheme"
ktesting "k8s.io/client-go/testing"
"opendev.org/airship/airshipctl/pkg/cluster/resetsatoken"
"opendev.org/airship/airshipctl/pkg/k8s/client/fake"
"opendev.org/airship/airshipctl/testutil"
)
type testCase struct {
name string
existingSecrets []*v1.Secret
existingPods []*v1.Pod
secretName string
secretNamespace string
numPodDeletes int
numSecretDeletes int
expectErr bool
}
var testCases = []testCase{
{
name: "no-pods-secrets",
expectErr: true,
},
{
name: "valid-secret-no-pod",
secretName: "valid-secret",
secretNamespace: "valid-namespace",
existingSecrets: []*v1.Secret{getSecret()},
numSecretDeletes: 1,
},
{
name: "valid-secret-no-pod-empty-filter",
secretNamespace: "valid-namespace",
existingSecrets: []*v1.Secret{getSecret()},
numSecretDeletes: 1,
},
{
name: "invalid-secret-no-pod",
secretName: "invalid-secret",
existingSecrets: []*v1.Secret{getSecret()},
secretNamespace: "valid-namespace",
},
{
name: "unmatched-secret-pod",
secretName: "invalid-secret",
secretNamespace: "valid-namespace",
existingPods: []*v1.Pod{getPod()},
existingSecrets: []*v1.Secret{getSecret()},
},
{
name: "matched-secret-pod",
secretName: "valid-secret",
secretNamespace: "valid-namespace",
existingPods: []*v1.Pod{getPod()},
existingSecrets: []*v1.Secret{getSecret()},
numPodDeletes: 1,
numSecretDeletes: 1,
},
}
func TestResetSaToken(t *testing.T) {
for _, testCase := range testCases {
cfg, _ := testutil.InitConfig(t)
var objects []runtime.Object
for _, pod := range testCase.existingPods {
objects = append(objects, pod)
}
for _, secret := range testCase.existingSecrets {
objects = append(objects, secret)
}
ra := fake.WithTypedObjects(objects...)
kclient := fake.NewClient(ra)
assert.NotEmpty(t, kclient)
assert.NotEmpty(t, cfg)
clientset := kclient.ClientSet()
manager, err := resetsatoken.NewTokenManager(clientset)
assert.NoError(t, err)
err = manager.RotateToken(testCase.secretNamespace, testCase.secretName)
if testCase.expectErr {
assert.Error(t, err)
continue
}
actions := clientset.(*kfake.Clientset).Actions()
podDeleteActions := filterActions(actions, "pods", "delete")
assert.Len(t, podDeleteActions, testCase.numPodDeletes)
secretDeleteActions := filterActions(actions, "secrets", "delete")
assert.Len(t, secretDeleteActions, testCase.numSecretDeletes)
}
}
func getSecret() *v1.Secret {
object := readObjectFromFile("testdata/secret.yaml")
if secret, ok := object.(*v1.Secret); ok {
return secret
}
return nil
}
func getPod() *v1.Pod {
object := readObjectFromFile("testdata/pod.yaml")
if pod, ok := object.(*v1.Pod); ok {
return pod
}
return nil
}
func readObjectFromFile(fileName string) runtime.Object {
contents, err := ioutil.ReadFile(fileName)
if err != nil {
return nil
}
jsonContents, err := yaml.ToJSON(contents)
if err != nil {
return nil
}
object, err := runtime.Decode(scheme.Codecs.UniversalDeserializer(), jsonContents)
if err != nil {
return nil
}
return object
}
func filterActions(actions []ktesting.Action, resource string, verb string) []ktesting.Action {
var result []ktesting.Action
for _, action := range actions {
if action.GetVerb() == verb && action.GetResource().Resource == resource {
result = append(result, action)
}
}
return result
}

View File

@ -1,21 +0,0 @@
apiVersion: airshipit.org/v1alpha1
contexts:
dummy_cluster:
manifest: dummy_manifest
currentContext: dummy_cluster
kind: Config
manifests:
dummy_manifest:
primaryRepositoryName: primary
repositories:
primary:
auth:
sshKey: testdata/test-key.pem
type: ssh-key
checkout:
branch: ""
force: false
remoteRef: ""
tag: v1.0.1
url: http://dummy.url.com/primary.git
targetPath: testdata

View File

@ -1,19 +0,0 @@
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNU1Ea3lPVEUzTURNd09Wb1hEVEk1TURreU5qRTNNRE13T1Zvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTUZyCkdxM0kyb2dZci81Y01Udy9Na1pORTNWQURzdEdyU240WjU2TDhPUGhMcUhDN2t1dno2dVpES3dCSGtGeTBNK2MKRXIzd2piUGE1aTV5NmkyMGtxSHBVMjdPZTA0dzBXV2s4N0RSZVlWaGNoZVJHRXoraWt3SndIcGRmMjJVemZNKwpkSDBzaUhuMVd6UnovYk4za3hMUzJlMnZ2U1Y3bmNubk1YRUd4OXV0MUY0NThHeWxxdmxXTUlWMzg5Q2didXFDCkcwcFdiMTBLM0RVZWdiT25Xa1FmSm5sTWRRVVZDUVdZZEZaaklrcWtkWi9hVTRobkNEV01oZXNWRnFNaDN3VVAKczhQay9BNWh1ZFFPbnFRNDVIWXZLdjZ5RjJWcDUyWExBRUx3NDJ4aVRKZlh0V1h4eHR6cU4wY1lyL2VxeS9XMQp1YVVGSW5xQjFVM0JFL1oxbmFrQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFKUUVKQVBLSkFjVDVuK3dsWGJsdU9mS0J3c2gKZTI4R1c5R2QwM0N0NGF3RzhzMXE1ZHNua2tpZmVTUENHVFZ1SXF6UTZDNmJaSk9SMDMvVEl5ejh6NDJnaitDVApjWUZXZkltM2RKTnpRL08xWkdySXZZNWdtcWJtWDlpV0JaU24rRytEOGxubzd2aGMvY0tBRFR5OTMvVU92MThuCkdhMnIrRGJJcHcyTWVBVEl2elpxRS9RWlVSQ25DMmdjUFhTVzFqN2h4R3o1a3ZNcGVDZTdQYVUvdVFvblVHSWsKZ2t6ZzI4NHQvREhUUzc4N1V1SUg5cXBaV09yTFNMOGFBeUxQUHhWSXBteGZmbWRETE9TS2VUemRlTmxoSitUMwowQlBVaHBQTlJBNTNJN0hRQjhVUDR2elNONTkzZ1VFbVlFQ2Jic2RYSzB6ZVR6SDdWWHR2Zmd5WTVWWT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
server: https://127.0.0.1:6443
name: dummycluster_ephemeral
contexts:
- context:
cluster: dummycluster_ephemeral
user: kubernetes-admin
name: dummy_cluster
current-context: dummy_cluster
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM4akNDQWRxZ0F3SUJBZ0lJQXhEdzk2RUY4SXN3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB4T1RBNU1qa3hOekF6TURsYUZ3MHlNREE1TWpneE56QXpNVEphTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXV6R0pZdlBaNkRvaTQyMUQKSzhXSmFaQ25OQWQycXo1cC8wNDJvRnpRUGJyQWd6RTJxWVZrek9MOHhBVmVSN1NONXdXb1RXRXlGOEVWN3JyLwo0K0hoSEdpcTVQbXF1SUZ5enpuNi9JWmM4alU5eEVmenZpa2NpckxmVTR2UlhKUXdWd2dBU05sMkFXQUloMmRECmRUcmpCQ2ZpS1dNSHlqMFJiSGFsc0J6T3BnVC9IVHYzR1F6blVRekZLdjJkajVWMU5rUy9ESGp5UlJKK0VMNlEKQlltR3NlZzVQNE5iQzllYnVpcG1NVEFxL0p1bU9vb2QrRmpMMm5acUw2Zkk2ZkJ0RjVPR2xwQ0IxWUo4ZnpDdApHUVFaN0hUSWJkYjJ0cDQzRlZPaHlRYlZjSHFUQTA0UEoxNSswV0F5bVVKVXo4WEE1NDRyL2J2NzRKY0pVUkZoCmFyWmlRd0lEQVFBQm95Y3dKVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFMMmhIUmVibEl2VHJTMFNmUVg1RG9ueVVhNy84aTg1endVWApSd3dqdzFuS0U0NDJKbWZWRGZ5b0hRYUM4Ti9MQkxyUXM0U0lqU1JYdmFHU1dSQnRnT1RRV21Db1laMXdSbjdwCndDTXZQTERJdHNWWm90SEZpUFl2b1lHWFFUSXA3YlROMmg1OEJaaEZ3d25nWUovT04zeG1rd29IN1IxYmVxWEYKWHF1TTluekhESk41VlZub1lQR09yRHMwWlg1RnNxNGtWVU0wVExNQm9qN1ZIRDhmU0E5RjRYNU4yMldsZnNPMAo4aksrRFJDWTAyaHBrYTZQQ0pQS0lNOEJaMUFSMG9ZakZxT0plcXpPTjBqcnpYWHh4S2pHVFVUb1BldVA5dCtCCjJOMVA1TnI4a2oxM0lrend5Q1NZclFVN09ZM3ltZmJobHkrcXZxaFVFa014MlQ1SkpmQT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBdXpHSll2UFo2RG9pNDIxREs4V0phWkNuTkFkMnF6NXAvMDQyb0Z6UVBickFnekUyCnFZVmt6T0w4eEFWZVI3U041d1dvVFdFeUY4RVY3cnIvNCtIaEhHaXE1UG1xdUlGeXp6bjYvSVpjOGpVOXhFZnoKdmlrY2lyTGZVNHZSWEpRd1Z3Z0FTTmwyQVdBSWgyZERkVHJqQkNmaUtXTUh5ajBSYkhhbHNCek9wZ1QvSFR2MwpHUXpuVVF6Rkt2MmRqNVYxTmtTL0RIanlSUkorRUw2UUJZbUdzZWc1UDROYkM5ZWJ1aXBtTVRBcS9KdW1Pb29kCitGakwyblpxTDZmSTZmQnRGNU9HbHBDQjFZSjhmekN0R1FRWjdIVEliZGIydHA0M0ZWT2h5UWJWY0hxVEEwNFAKSjE1KzBXQXltVUpVejhYQTU0NHIvYnY3NEpjSlVSRmhhclppUXdJREFRQUJBb0lCQVFDU0pycjlaeVpiQ2dqegpSL3VKMFZEWCt2aVF4c01BTUZyUjJsOE1GV3NBeHk1SFA4Vk4xYmc5djN0YUVGYnI1U3hsa3lVMFJRNjNQU25DCm1uM3ZqZ3dVQWlScllnTEl5MGk0UXF5VFBOU1V4cnpTNHRxTFBjM3EvSDBnM2FrNGZ2cSsrS0JBUUlqQnloamUKbnVFc1JpMjRzT3NESlM2UDE5NGlzUC9yNEpIM1M5bFZGbkVuOGxUR2c0M1kvMFZoMXl0cnkvdDljWjR5ZUNpNwpjMHFEaTZZcXJZaFZhSW9RRW1VQjdsbHRFZkZzb3l4VDR6RTE5U3pVbkRoMmxjYTF1TzhqcmI4d2xHTzBoQ2JyClB1R1l2WFFQa3Q0VlNmalhvdGJ3d2lBNFRCVERCRzU1bHp6MmNKeS9zSS8zSHlYbEMxcTdXUmRuQVhhZ1F0VzkKOE9DZGRkb0JBb0dCQU5NcUNtSW94REtyckhZZFRxT1M1ZFN4cVMxL0NUN3ZYZ0pScXBqd2Y4WHA2WHo0KzIvTAozVXFaVDBEL3dGTkZkc1Z4eFYxMnNYMUdwMHFWZVlKRld5OVlCaHVSWGpTZ0ZEWldSY1Z1Y01sNVpPTmJsbmZGCjVKQ0xnNXFMZ1g5VTNSRnJrR3A0R241UDQxamg4TnhKVlhzZG5xWE9xNTFUK1RRT1UzdkpGQjc1QW9HQkFPTHcKalp1cnZtVkZyTHdaVGgvRDNpWll5SVV0ZUljZ2NKLzlzbTh6L0pPRmRIbFd4dGRHUFVzYVd1MnBTNEhvckFtbgpqTm4vSTluUXd3enZ3MWUzVVFPbUhMRjVBczk4VU5hbk5TQ0xNMW1yaXZHRXJ1VHFnTDM1bU41eFZPdTUxQU5JCm4yNkFtODBJT2JDeEtLa0R0ZXJSaFhHd3g5c1pONVJCbG9VRThZNGJBb0dBQ3ZsdVhMZWRxcng5VkE0bDNoNXUKVDJXRVUxYjgxZ1orcmtRc1I1S0lNWEw4cllBTElUNUpHKzFuendyN3BkaEFXZmFWdVV2SDRhamdYT0h6MUs5aQpFODNSVTNGMG9ldUg0V01PY1RwU0prWm0xZUlXcWRiaEVCb1FGdUlWTXRib1BsV0d4ZUhFRHJoOEtreGp4aThSCmdEcUQyajRwY1IzQ0g5QjJ5a0lqQjVFQ2dZRUExc0xXLys2enE1c1lNSm14K1JXZThhTXJmL3pjQnVTSU1LQWgKY0dNK0wwMG9RSHdDaUU4TVNqcVN1ajV3R214YUFuanhMb3ZwSFlRV1VmUEVaUW95UE1YQ2VhRVBLOU4xbk8xMwp0V2lHRytIZkIxaU5PazFCc0lhNFNDbndOM1FRVTFzeXBaeEgxT3hueS9LYmkvYmEvWEZ5VzNqMGFUK2YvVWxrCmJGV1ZVdWtDZ1lFQTBaMmRTTFlmTjV5eFNtYk5xMWVqZXdWd1BjRzQxR2hQclNUZEJxdHFac1doWGE3aDdLTWEKeHdvamh5SXpnTXNyK2tXODdlajhDQ2h0d21sQ1p5QU92QmdOZytncnJ1cEZLM3FOSkpKeU9YREdHckdpbzZmTQp5aXB3Q2tZVGVxRThpZ1J6UkI5QkdFUGY4eVpjMUtwdmZhUDVhM0lRZmxiV0czbGpUemNNZVZjPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=

View File

@ -1,25 +0,0 @@
apiVersion: v1
kind: Pod
metadata:
name: valid-pod
namespace: valid-namespace
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: valid-pod-rs
spec:
containers:
- image: pod-image
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: valid-secret
readOnly: true
serviceAccount: valid-serviceaccount
serviceAccountName: valid-serviceaccount
volumes:
- name: valid-secret
secret:
defaultMode: 420
secretName: valid-secret

View File

@ -1,6 +0,0 @@
apiVersion: v1
kind: Secret
metadata:
name: valid-secret
namespace: valid-namespace
type: kubernetes.io/service-account-token