forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 1
/
link_secret_to_obj.go
172 lines (139 loc) · 4.75 KB
/
link_secret_to_obj.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
package secrets
import (
"errors"
"fmt"
"io"
"os"
"strings"
kapi "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"github.com/spf13/cobra"
)
// LinkSecretRecommendedName `oc secrets link`
const LinkSecretRecommendedName = "link"
var (
linkSecretLong = templates.LongDesc(`
Link secrets to a service account
Linking a secret enables a service account to automatically use that secret for some forms of authentication.`)
linkSecretExample = templates.Examples(`
# Add an image pull secret to a service account to automatically use it for pulling pod images:
%[1]s serviceaccount-name pull-secret --for=pull
# Add an image pull secret to a service account to automatically use it for both pulling and pushing build images:
%[1]s builder builder-image-secret --for=pull,mount
# If the cluster's serviceAccountConfig is operating with limitSecretReferences: True, secrets must be added to the pod's service account whitelist in order to be available to the pod:
%[1]s pod-sa pod-secret`)
)
type LinkSecretOptions struct {
SecretOptions
ForMount bool
ForPull bool
typeFlags []string
}
// NewCmdLinkSecret creates a command object for linking a secret reference to a service account
func NewCmdLinkSecret(name, fullName string, f kcmdutil.Factory, out io.Writer) *cobra.Command {
o := &LinkSecretOptions{SecretOptions{Out: out}, false, false, nil}
cmd := &cobra.Command{
Use: fmt.Sprintf("%s serviceaccounts-name secret-name [another-secret-name]...", name),
Short: "Link secrets to a ServiceAccount",
Long: linkSecretLong,
Example: fmt.Sprintf(linkSecretExample, fullName),
PreRun: func(cmd *cobra.Command, args []string) {
if len(os.Args) > 1 && os.Args[1] == "add" {
printDeprecationWarning("secrets add", "secrets link")
}
},
Run: func(c *cobra.Command, args []string) {
if err := o.Complete(f, args); err != nil {
kcmdutil.CheckErr(kcmdutil.UsageErrorf(c, err.Error()))
}
if err := o.Validate(); err != nil {
kcmdutil.CheckErr(kcmdutil.UsageErrorf(c, err.Error()))
}
if err := o.LinkSecrets(); err != nil {
kcmdutil.CheckErr(err)
}
},
}
cmd.Flags().StringSliceVar(&o.typeFlags, "for", []string{"mount"}, "type of secret to link: mount or pull")
return cmd
}
func (o *LinkSecretOptions) Complete(f kcmdutil.Factory, args []string) error {
if err := o.SecretOptions.Complete(f, args); err != nil {
return err
}
if len(o.typeFlags) == 0 {
o.ForMount = true
} else {
for _, flag := range o.typeFlags {
loweredValue := strings.ToLower(flag)
switch loweredValue {
case "pull":
o.ForPull = true
case "mount":
o.ForMount = true
default:
return fmt.Errorf("unknown for: %v", flag)
}
}
}
return nil
}
func (o LinkSecretOptions) Validate() error {
if err := o.SecretOptions.Validate(); err != nil {
return err
}
if !o.ForPull && !o.ForMount {
return errors.New("for must be present")
}
return nil
}
func (o LinkSecretOptions) LinkSecrets() error {
serviceaccount, err := o.GetServiceAccount()
if err != nil {
return err
}
err = o.linkSecretsToServiceAccount(serviceaccount)
if err != nil {
return err
}
return nil
}
// TODO: when Secrets in kapi.ServiceAccount get changed to MountSecrets and represented by LocalObjectReferences, this can be
// refactored to reuse the addition code better
// linkSecretsToServiceAccount links secrets to the service account, either as pull secrets, mount secrets, or both.
func (o LinkSecretOptions) linkSecretsToServiceAccount(serviceaccount *kapi.ServiceAccount) error {
updated := false
newSecrets, hasNotFound, err := o.GetSecrets(false)
if err != nil {
return err
}
newSecretNames := o.GetSecretNames(newSecrets)
if o.ForMount {
currentSecrets := o.GetMountSecretNames(serviceaccount)
secretsToLink := newSecretNames.Difference(currentSecrets)
for _, secretName := range secretsToLink.List() {
serviceaccount.Secrets = append(serviceaccount.Secrets, kapi.ObjectReference{Name: secretName})
updated = true
}
}
if o.ForPull {
currentSecrets := o.GetPullSecretNames(serviceaccount)
secretsToLink := newSecretNames.Difference(currentSecrets)
for _, secretName := range secretsToLink.List() {
serviceaccount.ImagePullSecrets = append(serviceaccount.ImagePullSecrets, kapi.LocalObjectReference{Name: secretName})
updated = true
}
}
if updated {
_, err = o.KubeCoreClient.ServiceAccounts(o.Namespace).Update(serviceaccount)
return err
}
if hasNotFound {
return errors.New("Some secrets could not be linked")
}
return nil
}
func printDeprecationWarning(command, alias string) {
fmt.Fprintf(os.Stderr, "%s is DEPRECATED and will be removed in a future version. Use %s instead.\n", alias, command)
}