/
refresh-keys.go
160 lines (138 loc) · 5.9 KB
/
refresh-keys.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
package ibmcloud
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pkg/errors"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"github.com/openshift/cloud-credential-operator/pkg/cmd/provisioning"
"github.com/openshift/cloud-credential-operator/pkg/ibmcloud"
)
// NewRefreshKeysCmd provides the "refresh-keys" subcommand
func NewRefreshKeysCmd() *cobra.Command {
refreshKeysCmd := &cobra.Command{
Use: "refresh-keys",
Short: "Refresh API Keys for the Service ID",
RunE: refreshKeysCmd,
}
refreshKeysCmd.PersistentFlags().StringVar(&Options.Name, "name", "", "User-defined name for all created IBM Cloud resources (can be separate from the cluster's infra-id)")
refreshKeysCmd.MarkPersistentFlagRequired("name")
refreshKeysCmd.PersistentFlags().StringVar(&Options.CredRequestDir, "credentials-requests-dir", "", "Directory containing files of CredentialsRequests to delete IAM Roles for (can be created by running 'oc adm release extract --credentials-requests --cloud=ibmcloud' against an OpenShift release image)")
refreshKeysCmd.MarkPersistentFlagRequired("credentials-requests-dir")
refreshKeysCmd.PersistentFlags().StringVar(&Options.KubeConfigFile, "kubeconfig", "", "absolute path to the kubeconfig file")
refreshKeysCmd.MarkPersistentFlagRequired("kubeconfig")
refreshKeysCmd.PersistentFlags().StringVar(&Options.ResourceGroupName, "resource-group-name", "", "Name of the resource group used for scoping the access policies")
refreshKeysCmd.PersistentFlags().BoolVar(&Options.Create, "create", false, "Create the ServiceID if does not exists")
refreshKeysCmd.PersistentFlags().BoolVar(&Options.EnableTechPreview, "enable-tech-preview", false, "Opt into processing CredentialsRequests marked as tech-preview")
return refreshKeysCmd
}
func refreshKeysCmd(cmd *cobra.Command, args []string) error {
apiKey := getEnv(APIKeyEnvVars)
if apiKey == "" {
return fmt.Errorf("%s environment variable not set", APIKeyEnvVars)
}
params := &ibmcloud.ClientParams{
InfraName: Options.Name,
}
ibmclient, err := ibmcloud.NewClient(apiKey, params)
if err != nil {
return err
}
apiKeyDetailsOptions := ibmclient.NewGetAPIKeysDetailsOptions()
apiKeyDetailsOptions.SetIamAPIKey(apiKey)
apiKeyDetails, _, err := ibmclient.GetAPIKeysDetails(apiKeyDetailsOptions)
if err != nil {
return errors.Wrap(err, "Failed to get details for the given APIKey")
}
cs, err := newClientset(Options.KubeConfigFile)
if err != nil {
return errors.Wrap(err, "Failed to create the kubernetes clientset")
}
err = refreshKeys(ibmclient, cs, apiKeyDetails.AccountID, Options.Name, Options.ResourceGroupName, Options.CredRequestDir, Options.Create, Options.EnableTechPreview)
if err != nil {
return errors.Wrap(err, "Failed to refresh keys")
}
return nil
}
func refreshKeys(ibmcloudClient ibmcloud.Client, kubeClient kubernetes.Interface, accountID *string, name, resourceGroupName, credReqDir string, create, enableTechPreview bool) error {
resourceGroupID, err := getResourceGroupID(ibmcloudClient, accountID, resourceGroupName)
if err != nil {
return errors.Wrap(err, "Failed to getResourceGroupID")
}
// Process directory
credReqs, err := provisioning.GetListOfCredentialsRequests(credReqDir, enableTechPreview)
if err != nil {
return errors.Wrap(err, "Failed to process files containing CredentialsRequests")
}
var serviceIDs []*ServiceID
for _, cr := range credReqs {
serviceID := NewServiceID(ibmcloudClient, name, *accountID, resourceGroupID, cr)
serviceIDs = append(serviceIDs, serviceID)
}
for _, serviceID := range serviceIDs {
list, err := serviceID.List()
if err != nil {
return errors.Wrapf(err, "Failed to check an existance for the ServiceID: %s", serviceID.name)
}
if len(list) == 0 && !create {
return fmt.Errorf("ServiceID: %s does not exist, rerun with --create flag to create it", serviceID.name)
}
if len(list) > 1 {
return fmt.Errorf("more than one ServiceID found with %s name, please delete the duplicate entries", serviceID.name)
}
}
for _, serviceID := range serviceIDs {
log.Printf("Refershing the token for ServiceID: %s", serviceID.name)
list, err := serviceID.List()
if err != nil {
return errors.Wrapf(err, "Failed to check an existance for the ServiceID: %s", serviceID.name)
}
if len(list) != 0 {
serviceID.ServiceID = &list[0]
if err := serviceID.Refresh(); err != nil {
return errors.Wrapf(err, "Failed to create API Key for ServiceID: %s", serviceID.name)
}
} else {
log.Printf("ServiceID does not exist, creating it.")
if err := serviceID.Do(); err != nil {
return errors.Wrap(err, "Failed to process the serviceID")
}
}
secret, err := serviceID.BuildSecret()
if err != nil {
return errors.Wrapf(err, "Failed to Dump the secret for the serviceID: %s", serviceID.name)
}
data, err := json.Marshal(secret)
if err != nil {
return errors.Wrapf(err, "Failed to Marshal")
}
log.Printf("Updating/Creating the secret: %s/%s for the serviceID: %s", secret.Namespace, secret.Name, serviceID.name)
//TODO(mkumatag): replace Patch() call with Apply() after k8s.io/client-go update to v1.21.0 or later
if _, err := kubeClient.CoreV1().Secrets(secret.Namespace).Patch(context.TODO(), secret.Name, types.ApplyPatchType, data, metav1.PatchOptions{FieldManager: "ccoctl"}); err != nil {
return errors.Wrapf(err, "Failed to create/update secret")
}
log.Printf("Removing the stale API Keys.")
err = serviceID.RemoveStaleKeys()
if err != nil {
return errors.Wrapf(err, "Failed to remove the stale API Keys")
}
}
return nil
}
func newClientset(kubeconfig string) (*kubernetes.Clientset, error) {
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
return nil, err
}
// create the clientset
cs, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, err
}
return cs, nil
}