Skip to content

Commit 15f2ddd

Browse files
committed
Token, subscription ID acquistion; refactoring
1 parent 5ddf0fc commit 15f2ddd

File tree

4 files changed

+132
-36
lines changed

4 files changed

+132
-36
lines changed

cmd/ciCloudLogin.go

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ var cloudLoginCmd = &cobra.Command{
4848
- "--aks-tenant-id" flag or "AKS_TENANT_ID" environment variable
4949
- "--aks-sp-app-id" flag or "AKS_SP_APP_ID" environment variable
5050
- "--aks-sp-password" flag or "AKS_SP_PASSWORD" environment variable
51+
- "--aks-subscription-id" flag or "AKS_SP_PASSWORD" environment variable
5152
`,
5253
Run: func(cmd *cobra.Command, args []string) {
5354

@@ -237,22 +238,37 @@ var cloudLoginCmd = &cobra.Command{
237238
log.Fatal("Cluster name required (cluster-name)")
238239
}
239240

240-
// command = fmt.Sprintf("az loginstring --service-principal --username '%s' --tenant '%s' --password '%s';", aksSPAppID, aksTenantID, aksSPPass)
241+
token, err := az.GetAuthToken(aksTenantID, aksSPAppID, aksSPPass)
242+
if err != nil {
243+
log.Fatalf("Error: %s", err)
244+
}
245+
246+
subscriptionID, err := az.GetDefaultSubscriptionID(token)
247+
if err != nil {
248+
log.Fatalf("Error: %s", err)
249+
}
241250

242251
// Create kubeconfig folder
243252
if _, err := os.Stat(filepath.Dir(kubeConfigPath)); os.IsNotExist(err) {
244253
_ = os.Mkdir(filepath.Dir(kubeConfigPath), 0750)
245254
}
246255

247-
ctx, cred := az.GetAzureCredentials(aksTenantID)
248-
config := az.GetKubeconfig(ctx, *cred, aksResourceGroup, aksSPAppID, clusterName)
256+
ctx, cred, err := az.GetAzureCredentials(aksTenantID)
257+
if err != nil {
258+
log.Fatalf("Error: %s", err)
259+
}
249260

250-
// Write custom cubeconfig to kube config file
251-
err := os.WriteFile(kubeConfigPath, config, 0700)
261+
config, err := az.GetKubeconfig(ctx, *cred, aksResourceGroup, subscriptionID, clusterName)
262+
if err != nil {
263+
log.Fatalf("Error: %s", err)
264+
}
265+
266+
// Write custom kubeconfig to kube config file
267+
err = os.WriteFile(kubeConfigPath, config, 0700)
252268
if err != nil {
253269
log.Fatal("Error writing kubeconfig:", err)
254270
}
255-
// command += fmt.Sprintf("az aks get-credentials --only-show-errors --resource-group '%s' --name '%s' --admin", aksResourceGroup, clusterName)
271+
256272
}
257273

258274
// Execute login commands

go.mod

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ require (
1717
)
1818

1919
require (
20-
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0 // indirect
21-
github.com/Azure/azure-sdk-for-go/sdk/internal v1.2.0 // indirect
20+
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.5.0 // indirect
21+
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect
2222
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
2323
)
2424

@@ -123,12 +123,12 @@ require (
123123
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect
124124
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
125125
golang.org/x/crypto v0.7.0 // indirect
126-
golang.org/x/net v0.8.0 // indirect
126+
golang.org/x/net v0.9.0 // indirect
127127
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
128128
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect
129-
golang.org/x/sys v0.6.0 // indirect
130-
golang.org/x/term v0.6.0 // indirect
131-
golang.org/x/text v0.8.0 // indirect
129+
golang.org/x/sys v0.7.0 // indirect
130+
golang.org/x/term v0.7.0 // indirect
131+
golang.org/x/text v0.9.0 // indirect
132132
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
133133
google.golang.org/appengine v1.6.7 // indirect
134134
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368 // indirect

go.sum

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,12 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
4646
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
4747
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
4848
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
49-
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0 h1:rTnT/Jrcm+figWlYz4Ixzt0SJVR2cMC8lvZcimipiEY=
50-
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0/go.mod h1:ON4tFdPTwRcgWEaVDrN3584Ef+b7GgSJaXxe5fW9t4M=
49+
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.5.0 h1:xGLAFFd9D3iLGxYiUGPdITSzsFmU1K8VtfuUHWAoN7M=
50+
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.5.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
5151
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.2 h1:uqM+VoHjVH6zdlkLF2b6O0ZANcHoj3rO0PoQ3jglUJA=
5252
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.2/go.mod h1:twTKAa1E6hLmSDjLhaCkbTMQKc7p/rNLU40rLxGEOCI=
53-
github.com/Azure/azure-sdk-for-go/sdk/internal v1.2.0 h1:leh5DwKv6Ihwi+h60uHtn6UWAxBbZ0q8DwQVMzf61zw=
54-
github.com/Azure/azure-sdk-for-go/sdk/internal v1.2.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
53+
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY=
54+
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM=
5555
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice v1.0.0 h1:figxyQZXzZQIcP3njhC68bYUiTw45J8/SsHaLW8Ax0M=
5656
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice v1.0.0/go.mod h1:TmlMW4W5OvXOmOyKNnor8nlMMiO1ctIyzmHme/VHsrA=
5757
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
@@ -855,8 +855,8 @@ golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qx
855855
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
856856
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
857857
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
858-
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
859-
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
858+
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
859+
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
860860
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
861861
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
862862
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -965,12 +965,12 @@ golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBc
965965
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
966966
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
967967
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
968-
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
969-
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
968+
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
969+
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
970970
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
971971
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
972-
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
973-
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
972+
golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
973+
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
974974
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
975975
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
976976
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -980,8 +980,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
980980
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
981981
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
982982
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
983-
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
984-
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
983+
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
984+
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
985985
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
986986
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
987987
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

internal/azure/ciAuth.go

Lines changed: 92 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,121 @@ package azure
22

33
import (
44
"context"
5-
"log"
5+
"encoding/json"
6+
"errors"
7+
"io"
8+
"net/http"
9+
"strings"
610

711
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
812
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice"
913
)
1014

11-
func GetAzureCredentials(tenantID string) (context.Context, *azidentity.AzureCLICredential) {
15+
type Subscription struct {
16+
SubscriptionID string `json:"subscriptionId"`
17+
}
18+
19+
// OAuth 2 token structure
20+
type tokenResponse struct {
21+
AccessToken string `json:"access_token"`
22+
TokenType string `json:"token_type"`
23+
ExpiresIn float64 `json:"expires_in"`
24+
ExtExpiresIn float64 `json:"ext_expires_in"`
25+
}
1226

13-
cred, err := azidentity.NewAzureCLICredential(&azidentity.AzureCLICredentialOptions{TenantID: tenantID})
27+
func GetAzureCredentials(tenantID string) (ctx context.Context, cred *azidentity.DefaultAzureCredential, err error) {
1428

29+
cred, err = azidentity.NewDefaultAzureCredential(&azidentity.DefaultAzureCredentialOptions{TenantID: tenantID})
1530
if err != nil {
16-
log.Fatal(err)
31+
return nil, nil, err
1732
}
18-
ctx := context.Background()
1933

20-
return ctx, cred
34+
ctx = context.Background()
35+
return ctx, cred, nil
2136
}
2237

23-
func GetKubeconfig(ctx context.Context, cred azidentity.AzureCLICredential, resourceGroupName string, subscriptionID string, clusterName string) (kubeconfig []byte) {
38+
func GetKubeconfig(ctx context.Context, cred azidentity.DefaultAzureCredential, resourceGroupName string, subscriptionID string, clusterName string) (kubeconfig []byte, err error) {
2439

2540
mcClient, err := armcontainerservice.NewManagedClustersClient(subscriptionID, &cred, nil)
2641
if err != nil {
27-
log.Fatal(err) //remake to return nil on error
42+
return nil, err
2843
}
2944

3045
resp, err := mcClient.ListClusterAdminCredentials(ctx, resourceGroupName, clusterName, nil)
3146
if err != nil {
32-
log.Fatal(err)
47+
return nil, err
3348
}
3449

3550
if len(resp.Kubeconfigs) > 0 {
36-
return resp.Kubeconfigs[0].Value
51+
return resp.Kubeconfigs[0].Value, nil
3752
} else {
38-
log.Fatal("Error: No Kubeconfigs are available")
39-
return
53+
return nil, errors.New("no kubeconfigs are available")
54+
}
55+
56+
}
57+
58+
// Returns the first subscription ID
59+
// If no IDs are found, 'empty' is set to true
60+
func GetDefaultSubscriptionID(token string) (subscriptionID string, err error) {
61+
62+
req, err := http.NewRequest(http.MethodGet, "https://management.azure.com/subscriptions?api-version=2020-01-01", nil)
63+
if err != nil {
64+
return "", err
65+
}
66+
req.Header.Set("Authorization", "Bearer "+token)
67+
68+
resp, err := http.DefaultClient.Do(req)
69+
if err != nil {
70+
return "", err
71+
}
72+
defer resp.Body.Close()
73+
74+
var subscriptions struct {
75+
Value []Subscription `json:"value"`
76+
}
77+
if err := json.NewDecoder(resp.Body).Decode(&subscriptions); err != nil {
78+
return "", err
4079
}
4180

81+
if len(subscriptions.Value) == 0 {
82+
return "", errors.New("no subscriptions found")
83+
}
84+
return subscriptions.Value[0].SubscriptionID, nil
85+
}
86+
87+
// Returns access token. Failing that, returns non-nil error
88+
// tenantId - Azure tenant ID
89+
// clientId - Client ID. Can pass Service Principal ID
90+
// clientSecret - Client secret. Cant pass Service Principal password
91+
func GetAuthToken(tenantId string, clientId string, clientSecret string) (string, error) {
92+
req, err := http.NewRequest(http.MethodPost, "https://login.microsoftonline.com/"+tenantId+"/oauth2/v2.0/token", nil)
93+
if err != nil {
94+
return "", err
95+
}
96+
97+
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
98+
99+
q := req.URL.Query()
100+
q.Add("grant_type", "client_credentials")
101+
q.Add("client_id", clientId)
102+
q.Add("client_secret", clientSecret)
103+
q.Add("scope", "https://management.azure.com/.default")
104+
105+
req.Body = io.NopCloser(strings.NewReader(q.Encode()))
106+
resp, err := http.DefaultClient.Do(req)
107+
if err != nil {
108+
return "", err
109+
}
110+
defer resp.Body.Close()
111+
112+
str, err := io.ReadAll(resp.Body)
113+
if err != nil {
114+
return "", err
115+
}
116+
117+
var token tokenResponse
118+
if err := json.Unmarshal(str, &token); err != nil {
119+
return "", err
120+
}
121+
return token.AccessToken, nil
42122
}

0 commit comments

Comments
 (0)