-
Notifications
You must be signed in to change notification settings - Fork 112
/
eks.go
93 lines (84 loc) · 3.13 KB
/
eks.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
package clusterauth
import (
"context"
"encoding/base64"
"fmt"
"time"
"github.com/aws/aws-sdk-go-v2/aws"
ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
"github.com/aws/aws-sdk-go-v2/service/sts"
smithyhttp "github.com/aws/smithy-go/transport/http"
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
"github.com/crossplane/crossplane-runtime/pkg/reconciler/managed"
"github.com/pkg/errors"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
)
const (
clusterIDHeader = "x-k8s-aws-id"
expireHeader = "X-Amz-Expires"
v1Prefix = "k8s-aws-v1."
errGetPresignGetCallerIdentity = "cannot get caller identity for presign"
errDecodeCA = "cannot decode certificate authority data"
errProduceKubeconfig = "cannot produce kubeconfig"
)
func newPresignClient(cfg aws.Config, optFns ...func(*sts.Options)) *sts.PresignClient {
cl := sts.NewFromConfig(cfg, optFns...)
return sts.NewPresignClient(cl)
}
// GetConnectionDetails extracts managed.ConnectionDetails out of ekstypes.Cluster.
func GetConnectionDetails(ctx context.Context, stsClient *sts.PresignClient, cluster *ekstypes.Cluster, expiration time.Duration) (managed.ConnectionDetails, error) {
getCallerIdentity, err := stsClient.PresignGetCallerIdentity(ctx, &sts.GetCallerIdentityInput{},
func(po *sts.PresignOptions) {
po.ClientOptions = []func(*sts.Options){
sts.WithAPIOptions(
smithyhttp.AddHeaderValue(clusterIDHeader, *cluster.Name),
// Required to provide.
// See https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
smithyhttp.AddHeaderValue(expireHeader, fmt.Sprintf("%d", int(expiration.Seconds()))),
),
}
},
)
if err != nil {
return nil, errors.Wrap(err, errGetPresignGetCallerIdentity)
}
// More information: https://docs.aws.amazon.com/eks/latest/userguide/create-kubeconfig.html
token := v1Prefix + base64.RawURLEncoding.EncodeToString([]byte(getCallerIdentity.URL))
// NOTE(hasheddan): We must decode the CA data before constructing our
// Kubeconfig, as the raw Kubeconfig will be base64 encoded again when
// written as a Secret.
caData, err := base64.StdEncoding.DecodeString(aws.ToString(cluster.CertificateAuthority.Data))
if err != nil {
return managed.ConnectionDetails{}, errors.Wrap(err, errDecodeCA)
}
kc := clientcmdapi.Config{
Clusters: map[string]*clientcmdapi.Cluster{
*cluster.Name: {
Server: *cluster.Endpoint,
CertificateAuthorityData: caData,
},
},
Contexts: map[string]*clientcmdapi.Context{
*cluster.Name: {
Cluster: *cluster.Name,
AuthInfo: *cluster.Name,
},
},
AuthInfos: map[string]*clientcmdapi.AuthInfo{
*cluster.Name: {
Token: token,
},
},
CurrentContext: *cluster.Name,
}
rawConfig, err := clientcmd.Write(kc)
if err != nil {
return managed.ConnectionDetails{}, errors.Wrap(err, errProduceKubeconfig)
}
return managed.ConnectionDetails{
xpv1.ResourceCredentialsSecretEndpointKey: []byte(*cluster.Endpoint),
xpv1.ResourceCredentialsSecretKubeconfigKey: rawConfig,
xpv1.ResourceCredentialsSecretCAKey: caData,
}, nil
}