-
Notifications
You must be signed in to change notification settings - Fork 85
/
create.go
219 lines (190 loc) · 7.79 KB
/
create.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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
package serviceaccount
import (
"context"
"fmt"
"time"
"github.com/microsoftgraph/msgraph-sdk-go/models"
"github.com/spf13/cobra"
"monis.app/mlog"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/Azure/azure-workload-identity/pkg/cloud"
"github.com/Azure/azure-workload-identity/pkg/cmd/serviceaccount/auth"
"github.com/Azure/azure-workload-identity/pkg/cmd/serviceaccount/options"
phases "github.com/Azure/azure-workload-identity/pkg/cmd/serviceaccount/phases/create"
"github.com/Azure/azure-workload-identity/pkg/cmd/serviceaccount/phases/workflow"
"github.com/Azure/azure-workload-identity/pkg/cmd/serviceaccount/util"
"github.com/Azure/azure-workload-identity/pkg/kuberneteshelper"
"github.com/Azure/azure-workload-identity/pkg/webhook"
)
func newCreateCmd(authProvider auth.Provider) *cobra.Command {
createRunner := workflow.NewPhaseRunner()
data := &createData{
authProvider: authProvider,
}
cmd := &cobra.Command{
Use: "create",
RunE: func(cmd *cobra.Command, args []string) error {
return createRunner.Run(data)
},
}
f := cmd.Flags()
f.StringVar(&data.serviceAccountName, options.ServiceAccountName.Flag, "", options.ServiceAccountName.Description)
f.StringVar(&data.serviceAccountNamespace, options.ServiceAccountNamespace.Flag, "default", options.ServiceAccountNamespace.Description)
f.StringVar(&data.serviceAccountIssuerURL, options.ServiceAccountIssuerURL.Flag, "", options.ServiceAccountIssuerURL.Description)
f.DurationVar(&data.serviceAccountTokenExpiration, options.ServiceAccountTokenExpiration.Flag, time.Duration(webhook.DefaultServiceAccountTokenExpiration)*time.Second, options.ServiceAccountTokenExpiration.Description)
f.StringVar(&data.aadApplicationName, options.AADApplicationName.Flag, "", options.AADApplicationName.Description)
f.StringVar(&data.aadApplicationClientID, options.AADApplicationClientID.Flag, "", options.AADApplicationClientID.Description)
f.StringVar(&data.aadApplicationObjectID, options.AADApplicationObjectID.Flag, "", options.AADApplicationObjectID.Description)
f.StringVar(&data.servicePrincipalName, options.ServicePrincipalName.Flag, "", options.ServicePrincipalName.Description)
f.StringVar(&data.servicePrincipalObjectID, options.ServicePrincipalObjectID.Flag, "", options.ServicePrincipalObjectID.Description)
f.StringVar(&data.azureScope, options.AzureScope.Flag, "", options.AzureScope.Description)
f.StringVar(&data.azureRole, options.AzureRole.Flag, "", options.AzureRole.Description)
// append phases in order
createRunner.AppendPhases(
phases.NewAADApplicationPhase(),
phases.NewServiceAccountPhase(),
phases.NewFederatedIdentityPhase(),
phases.NewRoleAssignmentPhase(),
)
createRunner.BindToCommand(cmd, data)
return cmd
}
// createData is an implementation of phases.CreateData in
// pkg/cmd/serviceaccount/phases/create/data.go
type createData struct {
serviceAccountName string
serviceAccountNamespace string
serviceAccountIssuerURL string
serviceAccountTokenExpiration time.Duration
aadApplication models.Applicationable // cache
aadApplicationName string
aadApplicationClientID string
aadApplicationObjectID string
servicePrincipal models.ServicePrincipalable // cache
servicePrincipalObjectID string
servicePrincipalName string
azureRole string
azureScope string
authProvider auth.Provider
}
var _ phases.CreateData = &createData{}
// ServiceAccountName returns the name of the service account.
func (c *createData) ServiceAccountName() string {
return c.serviceAccountName
}
// ServiceAccountNamespace returns the namespace of the service account.
func (c *createData) ServiceAccountNamespace() string {
return c.serviceAccountNamespace
}
// ServiceAccountIssuerURL returns the issuer URL of the service account.
func (c *createData) ServiceAccountIssuerURL() string {
return c.serviceAccountIssuerURL
}
// ServiceAccountTokenExpiration returns the expiration time of the service account token.
func (c *createData) ServiceAccountTokenExpiration() time.Duration {
return c.serviceAccountTokenExpiration
}
// AADApplication returns the AAD application object.
// This will return the cached value if it has been created.
func (c *createData) AADApplication() (models.Applicationable, error) {
if c.aadApplication == nil {
app, err := c.AzureClient().GetApplication(context.Background(), c.AADApplicationName())
if err != nil {
return nil, err
}
c.aadApplication = app
}
return c.aadApplication, nil
}
// AADApplicationName returns the name of the AAD application.
func (c *createData) AADApplicationName() string {
name := c.aadApplicationName
if name == "" {
if c.ServiceAccountNamespace() != "" && c.ServiceAccountName() != "" && c.ServiceAccountIssuerURL() != "" {
mlog.Warning("--aad-application-name not specified, constructing name with service account namespace, name, and the hash of the issuer URL")
name = fmt.Sprintf("%s-%s-%s", c.ServiceAccountNamespace(), c.serviceAccountName, util.GetIssuerHash(c.ServiceAccountIssuerURL()))
}
}
return name
}
// AADApplicationClientID returns the client ID of the AAD application.
// This will be used for annotating the service account.
func (c *createData) AADApplicationClientID() string {
if c.aadApplicationClientID != "" {
return c.aadApplicationClientID
}
app, err := c.AADApplication()
if err != nil {
mlog.Error("failed to get AAD application client ID. Returning an empty string", err)
return ""
}
return *app.GetAppId()
}
// AADApplicationObjectID returns the object ID of the AAD application.
// This will be used for creating or removing the federated identity credential.
func (c *createData) AADApplicationObjectID() string {
if c.aadApplicationObjectID != "" {
return c.aadApplicationObjectID
}
app, err := c.AADApplication()
if err != nil {
mlog.Error("failed to get AAD application object ID. Returning an empty string", err)
return ""
}
return *app.GetId()
}
// ServicePrincipal returns the service principal object.
// This will return the cached value if it has been created.
func (c *createData) ServicePrincipal() (models.ServicePrincipalable, error) {
if c.servicePrincipal == nil {
sp, err := c.AzureClient().GetServicePrincipal(context.Background(), c.ServicePrincipalName())
if err != nil {
return nil, err
}
c.servicePrincipal = sp
}
return c.servicePrincipal, nil
}
// ServicePrincipalName returns the name of the service principal.
func (c *createData) ServicePrincipalName() string {
name := c.servicePrincipalName
// fall back to the name of the AAD application
if name == "" {
mlog.Warning("--service-principal-name not specified, falling back to AAD application name")
name = c.AADApplicationName()
}
return name
}
// ServicePrincipalObjectID returns the object ID of the service principal.
// This will be used for creating or removing the role assignment.
func (c *createData) ServicePrincipalObjectID() string {
if c.servicePrincipalObjectID != "" {
return c.servicePrincipalObjectID
}
sp, err := c.ServicePrincipal()
if err != nil {
mlog.Error("failed to get service principal object ID. Returning an empty string", err)
return ""
}
return *sp.GetId()
}
// AzureRole returns the Azure role.
func (c *createData) AzureRole() string {
return c.azureRole
}
// AzureScope returns the Azure scope.
func (c *createData) AzureScope() string {
return c.azureScope
}
// AzureTenantID returns the Azure tenant ID.
func (c *createData) AzureTenantID() string {
return c.authProvider.GetAzureTenantID()
}
// AzureClient returns the Azure client.
func (c *createData) AzureClient() cloud.Interface {
return c.authProvider.GetAzureClient()
}
// KubeClient returns the Kubernetes client.
func (c *createData) KubeClient() (client.Client, error) {
return kuberneteshelper.GetKubeClient()
}