mirror of
https://github.com/open-cluster-management-io/ocm.git
synced 2026-08-19 04:06:35 +00:00
✨ Miscellaneous code cleanup (#881)
Scorecard supply-chain security / Scorecard analysis (push) Waiting to run
Post / coverage (push) Waiting to run
Post / images (amd64) (push) Waiting to run
Post / images (arm64) (push) Waiting to run
Post / image manifest (push) Blocked by required conditions
Post / trigger clusteradm e2e (push) Blocked by required conditions
Scorecard supply-chain security / Scorecard analysis (push) Waiting to run
Post / coverage (push) Waiting to run
Post / images (amd64) (push) Waiting to run
Post / images (arm64) (push) Waiting to run
Post / image manifest (push) Blocked by required conditions
Post / trigger clusteradm e2e (push) Blocked by required conditions
* extract constants and remove permissions Signed-off-by: Alex <alexchan2988@gmail.com> * Addressing miscellaneous code cleanup Signed-off-by: Gaurav Jaswal <jaswalkiranavtar@gmail.com> --------- Signed-off-by: Alex <alexchan2988@gmail.com> Signed-off-by: Gaurav Jaswal <jaswalkiranavtar@gmail.com> Co-authored-by: Alex <alexchan2988@gmail.com>
This commit is contained in:
@@ -121,10 +121,6 @@ spec:
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.name
|
||||
{{if eq .RegistrationDriver.AuthType "awsirsa"}}
|
||||
- name: PATH
|
||||
value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/awscli/dist
|
||||
{{end}}
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
|
||||
@@ -107,10 +107,6 @@ spec:
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.name
|
||||
{{if eq .RegistrationDriver.AuthType "awsirsa"}}
|
||||
- name: PATH
|
||||
value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/awscli/dist
|
||||
{{end}}
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
|
||||
@@ -92,10 +92,6 @@ spec:
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.name
|
||||
{{if eq .RegistrationDriver.AuthType "awsirsa"}}
|
||||
- name: PATH
|
||||
value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/awscli/dist
|
||||
{{end}}
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"eks:DescribeCluster",
|
||||
"eks:ListClusters"
|
||||
],
|
||||
"Resource": "{{.hubClusterArn}}"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
package helpers
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"crypto/md5" // #nosec G501
|
||||
"encoding/hex"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GetAwsAccountIdAndClusterName Parses aws accountId and cluster-name from clusterArn
|
||||
// e.g. if clusterArn is arn:aws:eks:us-west-2:123456789012:cluster/hub-cluster1
|
||||
@@ -19,3 +23,8 @@ func GetAwsRegion(clusterArn string) string {
|
||||
clusterStringParts := strings.Split(clusterArn, ":")
|
||||
return clusterStringParts[3]
|
||||
}
|
||||
|
||||
func Md5HashSuffix(hubClusterAccountId string, hubClusterName string, managedClusterAccountId string, managedClusterName string) string {
|
||||
hash := md5.Sum([]byte(strings.Join([]string{hubClusterAccountId, hubClusterName, managedClusterAccountId, managedClusterName}, "#"))) // #nosec G401
|
||||
return hex.EncodeToString(hash[:])
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package helpers
|
||||
|
||||
const (
|
||||
AwsIrsaAuthType = "awsirsa"
|
||||
CSRAuthType = "csr"
|
||||
)
|
||||
@@ -1,12 +0,0 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"crypto/md5" // #nosec G501
|
||||
"encoding/hex"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Md5HashSuffix(hubClusterAccountId string, hubClusterName string, managedClusterAccountId string, managedClusterName string) string {
|
||||
hash := md5.Sum([]byte(strings.Join([]string{hubClusterAccountId, hubClusterName, managedClusterAccountId, managedClusterName}, "#"))) // #nosec G401
|
||||
return hex.EncodeToString(hash[:])
|
||||
}
|
||||
+1
-1
@@ -427,7 +427,7 @@ func (n *clusterManagerController) getImagePullSecret(ctx context.Context) (stri
|
||||
func getIdentityCreatorRoleAndTags(cm operatorapiv1.ClusterManager) string {
|
||||
if cm.Spec.RegistrationConfiguration != nil {
|
||||
for _, registrationDriver := range cm.Spec.RegistrationConfiguration.RegistrationDrivers {
|
||||
if registrationDriver.AuthType == "awsirsa" && registrationDriver.AwsIrsa != nil {
|
||||
if registrationDriver.AuthType == commonhelper.AwsIrsaAuthType && registrationDriver.AwsIrsa != nil {
|
||||
hubClusterArn := registrationDriver.AwsIrsa.HubClusterArn
|
||||
hubClusterAccountId, hubClusterName := commonhelper.GetAwsAccountIdAndClusterName(hubClusterArn)
|
||||
return "arn:aws:iam::" + hubClusterAccountId + ":role/" + hubClusterName + "_managed-cluster-identity-creator"
|
||||
|
||||
+3
-2
@@ -21,6 +21,7 @@ import (
|
||||
operatorapiv1 "open-cluster-management.io/api/operator/v1"
|
||||
|
||||
"open-cluster-management.io/ocm/manifests"
|
||||
commonhelpers "open-cluster-management.io/ocm/pkg/common/helpers"
|
||||
"open-cluster-management.io/ocm/pkg/operator/helpers"
|
||||
)
|
||||
|
||||
@@ -77,11 +78,11 @@ func (c *runtimeReconcile) reconcile(ctx context.Context, cm *operatorapiv1.Clus
|
||||
var enabledRegistrationDrivers []string
|
||||
for _, registrationDriver := range cm.Spec.RegistrationConfiguration.RegistrationDrivers {
|
||||
enabledRegistrationDrivers = append(enabledRegistrationDrivers, registrationDriver.AuthType)
|
||||
if registrationDriver.AuthType == "awsirsa" && registrationDriver.AwsIrsa != nil {
|
||||
if registrationDriver.AuthType == commonhelpers.AwsIrsaAuthType && registrationDriver.AwsIrsa != nil {
|
||||
config.HubClusterArn = registrationDriver.AwsIrsa.HubClusterArn
|
||||
config.AutoApprovedARNPatterns = strings.Join(registrationDriver.AwsIrsa.AutoApprovedIdentities, ",")
|
||||
config.AwsResourceTags = strings.Join(registrationDriver.AwsIrsa.Tags, ",")
|
||||
} else if registrationDriver.AuthType == "csr" && registrationDriver.CSR != nil {
|
||||
} else if registrationDriver.AuthType == commonhelpers.CSRAuthType && registrationDriver.CSR != nil {
|
||||
config.AutoApprovedCSRUsers = strings.Join(registrationDriver.CSR.AutoApprovedIdentities, ",")
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -42,7 +42,6 @@ const (
|
||||
klusterletFinalizer = "operator.open-cluster-management.io/klusterlet-cleanup"
|
||||
managedResourcesEvictionTimestampAnno = "operator.open-cluster-management.io/managed-resources-eviction-timestamp"
|
||||
klusterletNamespaceLabelKey = "operator.open-cluster-management.io/klusterlet"
|
||||
AwsIrsaAuthType = "awsirsa"
|
||||
)
|
||||
|
||||
type klusterletController struct {
|
||||
@@ -346,7 +345,7 @@ func (n *klusterletController) sync(ctx context.Context, controllerContext facto
|
||||
config.RegistrationKubeAPIBurst = klusterlet.Spec.RegistrationConfiguration.KubeAPIBurst
|
||||
// Configuring Registration driver depending on registration auth
|
||||
if &klusterlet.Spec.RegistrationConfiguration.RegistrationDriver != nil &&
|
||||
klusterlet.Spec.RegistrationConfiguration.RegistrationDriver.AuthType == AwsIrsaAuthType {
|
||||
klusterlet.Spec.RegistrationConfiguration.RegistrationDriver.AuthType == commonhelpers.AwsIrsaAuthType {
|
||||
|
||||
hubClusterArn := klusterlet.Spec.RegistrationConfiguration.RegistrationDriver.AwsIrsa.HubClusterArn
|
||||
managedClusterArn := klusterlet.Spec.RegistrationConfiguration.RegistrationDriver.AwsIrsa.ManagedClusterArn
|
||||
|
||||
+4
-3
@@ -42,6 +42,7 @@ import (
|
||||
"open-cluster-management.io/sdk-go/pkg/patcher"
|
||||
|
||||
"open-cluster-management.io/ocm/manifests"
|
||||
commonhelpers "open-cluster-management.io/ocm/pkg/common/helpers"
|
||||
testingcommon "open-cluster-management.io/ocm/pkg/common/testing"
|
||||
"open-cluster-management.io/ocm/pkg/operator/helpers"
|
||||
testinghelper "open-cluster-management.io/ocm/pkg/operator/helpers/testing"
|
||||
@@ -1012,7 +1013,7 @@ func TestGetServersFromKlusterlet(t *testing.T) {
|
||||
func TestAWSIrsaAuthInSingletonModeWithInvalidClusterArns(t *testing.T) {
|
||||
klusterlet := newKlusterlet("klusterlet", "testns", "cluster1")
|
||||
awsIrsaRegistrationDriver := operatorapiv1.RegistrationDriver{
|
||||
AuthType: AwsIrsaAuthType,
|
||||
AuthType: commonhelpers.AwsIrsaAuthType,
|
||||
AwsIrsa: &operatorapiv1.AwsIrsa{
|
||||
HubClusterArn: "arn:aws:bks:us-west-2:123456789012:cluster/hub-cluster1",
|
||||
ManagedClusterArn: "arn:aws:eks:us-west-2:123456789012:cluster/managed-cluster1",
|
||||
@@ -1043,7 +1044,7 @@ func TestAWSIrsaAuthInSingletonModeWithInvalidClusterArns(t *testing.T) {
|
||||
func TestAWSIrsaAuthInSingletonMode(t *testing.T) {
|
||||
klusterlet := newKlusterlet("klusterlet", "testns", "cluster1")
|
||||
awsIrsaRegistrationDriver := operatorapiv1.RegistrationDriver{
|
||||
AuthType: AwsIrsaAuthType,
|
||||
AuthType: commonhelpers.AwsIrsaAuthType,
|
||||
AwsIrsa: &operatorapiv1.AwsIrsa{
|
||||
HubClusterArn: "arn:aws:eks:us-west-2:123456789012:cluster/hub-cluster1",
|
||||
ManagedClusterArn: "arn:aws:eks:us-west-2:123456789012:cluster/managed-cluster1",
|
||||
@@ -1075,7 +1076,7 @@ func TestAWSIrsaAuthInSingletonMode(t *testing.T) {
|
||||
func TestAWSIrsaAuthInNonSingletonMode(t *testing.T) {
|
||||
klusterlet := newKlusterlet("klusterlet", "testns", "cluster1")
|
||||
awsIrsaRegistrationDriver := operatorapiv1.RegistrationDriver{
|
||||
AuthType: AwsIrsaAuthType,
|
||||
AuthType: commonhelpers.AwsIrsaAuthType,
|
||||
AwsIrsa: &operatorapiv1.AwsIrsa{
|
||||
HubClusterArn: "arn:aws:eks:us-west-2:123456789012:cluster/hub-cluster1",
|
||||
ManagedClusterArn: "arn:aws:eks:us-west-2:123456789012:cluster/managed-cluster1",
|
||||
|
||||
@@ -64,7 +64,7 @@ func NewHubManagerOptions() *HubManagerOptions {
|
||||
GCResourceList: []string{"addon.open-cluster-management.io/v1alpha1/managedclusteraddons",
|
||||
"work.open-cluster-management.io/v1/manifestworks"},
|
||||
ImportOption: importeroptions.New(),
|
||||
EnabledRegistrationDrivers: []string{"csr"},
|
||||
EnabledRegistrationDrivers: []string{commonhelpers.CSRAuthType},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ func (m *HubManagerOptions) RunControllerManagerWithInformers(
|
||||
var drivers []register.HubDriver
|
||||
for _, enabledRegistrationDriver := range m.EnabledRegistrationDrivers {
|
||||
switch enabledRegistrationDriver {
|
||||
case "csr":
|
||||
case commonhelpers.CSRAuthType:
|
||||
autoApprovedCSRUsers := m.ClusterAutoApprovalUsers
|
||||
if len(m.AutoApprovedCSRUsers) > 0 {
|
||||
autoApprovedCSRUsers = m.AutoApprovedCSRUsers
|
||||
@@ -180,7 +180,7 @@ func (m *HubManagerOptions) RunControllerManagerWithInformers(
|
||||
return err
|
||||
}
|
||||
drivers = append(drivers, csrDriver)
|
||||
case "awsirsa":
|
||||
case commonhelpers.AwsIrsaAuthType:
|
||||
awsIRSAHubDriver, err := awsirsa.NewAWSIRSAHubDriver(ctx, m.HubClusterArn, m.AutoApprovedARNPatterns, m.AwsResourceTags)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -64,7 +64,7 @@ func (c *AWSIRSADriver) BuildKubeConfigFromTemplate(kubeConfig *clientcmdapi.Con
|
||||
kubeConfig.AuthInfos = map[string]*clientcmdapi.AuthInfo{register.DefaultKubeConfigAuth: {
|
||||
Exec: &clientcmdapi.ExecConfig{
|
||||
APIVersion: "client.authentication.k8s.io/v1beta1",
|
||||
Command: "aws",
|
||||
Command: "/awscli/dist/aws",
|
||||
Args: []string{
|
||||
"--region",
|
||||
awsRegion,
|
||||
|
||||
@@ -58,7 +58,7 @@ func TestBuildKubeconfig(t *testing.T) {
|
||||
server: "https://127.0.0.1:6443",
|
||||
AuthInfoExec: &clientcmdapi.ExecConfig{
|
||||
APIVersion: "client.authentication.k8s.io/v1beta1",
|
||||
Command: "aws",
|
||||
Command: "/awscli/dist/aws",
|
||||
Args: []string{
|
||||
"--region",
|
||||
"us-west-2",
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
|
||||
clusterv1 "open-cluster-management.io/api/cluster/v1"
|
||||
v1 "open-cluster-management.io/api/cluster/v1"
|
||||
operatorv1 "open-cluster-management.io/api/operator/v1"
|
||||
|
||||
"open-cluster-management.io/ocm/manifests"
|
||||
commonhelpers "open-cluster-management.io/ocm/pkg/common/helpers"
|
||||
@@ -27,8 +28,9 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
errNoSuchEntity = "NoSuchEntity"
|
||||
errEntityAlreadyExists = "EntityAlreadyExists"
|
||||
errNoSuchEntity = "NoSuchEntity"
|
||||
errEntityAlreadyExists = "EntityAlreadyExists"
|
||||
trustPolicyTemplatePath = "managed-cluster-policy/TrustPolicy.tmpl"
|
||||
)
|
||||
|
||||
type AWSIRSAHubDriver struct {
|
||||
@@ -46,7 +48,7 @@ func (a *AWSIRSAHubDriver) Accept(cluster *clusterv1.ManagedCluster) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
managedClusterArn := cluster.Annotations["agent.open-cluster-management.io/managed-cluster-arn"]
|
||||
managedClusterArn := cluster.Annotations[operatorv1.ClusterAnnotationsKeyPrefix+"/"+ManagedClusterArn]
|
||||
for _, p := range a.autoApprovedARNPatterns {
|
||||
// Ensure the pattern matches the entire managed cluster ARN
|
||||
if p.FindString(managedClusterArn) == managedClusterArn && len(managedClusterArn) > 0 {
|
||||
@@ -59,8 +61,8 @@ func (a *AWSIRSAHubDriver) Accept(cluster *clusterv1.ManagedCluster) bool {
|
||||
// Cleanup is run when the cluster is deleting or hubAcceptClient is set false
|
||||
func (c *AWSIRSAHubDriver) Cleanup(ctx context.Context, managedCluster *clusterv1.ManagedCluster) error {
|
||||
_, isManagedClusterIamRoleSuffixPresent :=
|
||||
managedCluster.Annotations["agent.open-cluster-management.io/managed-cluster-iam-role-suffix"]
|
||||
_, isManagedClusterArnPresent := managedCluster.Annotations["agent.open-cluster-management.io/managed-cluster-arn"]
|
||||
managedCluster.Annotations[operatorv1.ClusterAnnotationsKeyPrefix+"/"+ManagedClusterIAMRoleSuffix]
|
||||
_, isManagedClusterArnPresent := managedCluster.Annotations[operatorv1.ClusterAnnotationsKeyPrefix+"/"+ManagedClusterArn]
|
||||
|
||||
logger := klog.FromContext(ctx)
|
||||
|
||||
@@ -69,13 +71,13 @@ func (c *AWSIRSAHubDriver) Cleanup(ctx context.Context, managedCluster *clusterv
|
||||
return nil
|
||||
}
|
||||
|
||||
roleName, _, roleArn, policyArn, err := getRoleAndPolicyArn(ctx, managedCluster, c.cfg)
|
||||
roleName, roleArn, err := getRoleNameAndArn(ctx, managedCluster, c.cfg)
|
||||
if err != nil {
|
||||
logger.V(4).Error(err, "Failed to getRoleAndPolicyArn")
|
||||
logger.V(4).Error(err, "Failed to getRoleNameAndArn")
|
||||
return err
|
||||
}
|
||||
|
||||
err = deleteIAMRoleAndPolicy(ctx, c.cfg, roleName, policyArn)
|
||||
err = deleteIAMRole(ctx, c.cfg, roleName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -95,8 +97,8 @@ func (c *AWSIRSAHubDriver) Run(_ context.Context, _ int) {
|
||||
}
|
||||
|
||||
func (a *AWSIRSAHubDriver) allows(cluster *clusterv1.ManagedCluster) bool {
|
||||
_, isManagedClusterArnPresent := cluster.Annotations["agent.open-cluster-management.io/managed-cluster-arn"]
|
||||
_, isManagedClusterIAMRoleSuffixPresent := cluster.Annotations["agent.open-cluster-management.io/managed-cluster-iam-role-suffix"]
|
||||
_, isManagedClusterArnPresent := cluster.Annotations[operatorv1.ClusterAnnotationsKeyPrefix+"/"+ManagedClusterArn]
|
||||
_, isManagedClusterIAMRoleSuffixPresent := cluster.Annotations[operatorv1.ClusterAnnotationsKeyPrefix+"/"+ManagedClusterIAMRoleSuffix]
|
||||
return isManagedClusterArnPresent && isManagedClusterIAMRoleSuffixPresent
|
||||
}
|
||||
|
||||
@@ -123,7 +125,7 @@ func (a *AWSIRSAHubDriver) CreatePermissions(ctx context.Context, cluster *clust
|
||||
}
|
||||
|
||||
// This function creates:
|
||||
// 1. IAM Role and Policy in the hub cluster IAM
|
||||
// 1. IAM Role and Trust Policy in the hub cluster IAM
|
||||
// 2. Returns the hubClusterName and the roleArn to be used for Access Entry creation
|
||||
func createIAMRoleAndPolicy(ctx context.Context, hubClusterArn string, managedCluster *v1.ManagedCluster, cfg aws.Config,
|
||||
awsResourceTags []string) (string, string, error) {
|
||||
@@ -139,15 +141,15 @@ func createIAMRoleAndPolicy(ctx context.Context, hubClusterArn string, managedCl
|
||||
iamClient := iam.NewFromConfig(cfg)
|
||||
|
||||
managedClusterIamRoleSuffix, isManagedClusterIamRoleSuffixPresent :=
|
||||
managedCluster.Annotations["agent.open-cluster-management.io/managed-cluster-iam-role-suffix"]
|
||||
managedClusterArn, isManagedClusterArnPresent := managedCluster.Annotations["agent.open-cluster-management.io/managed-cluster-arn"]
|
||||
managedCluster.Annotations[operatorv1.ClusterAnnotationsKeyPrefix+"/"+ManagedClusterIAMRoleSuffix]
|
||||
managedClusterArn, isManagedClusterArnPresent := managedCluster.Annotations[operatorv1.ClusterAnnotationsKeyPrefix+"/"+ManagedClusterArn]
|
||||
|
||||
hubAccountId, hubClusterName = commonhelpers.GetAwsAccountIdAndClusterName(hubClusterArn)
|
||||
managedClusterAccountId, managedClusterName = commonhelpers.GetAwsAccountIdAndClusterName(managedClusterArn)
|
||||
|
||||
roleName, policyName, roleArn, policyArn, err := getRoleAndPolicyArn(ctx, managedCluster, cfg)
|
||||
roleName, roleArn, err := getRoleNameAndArn(ctx, managedCluster, cfg)
|
||||
if err != nil {
|
||||
logger.V(4).Error(err, "Failed to getRoleAndPolicyArn")
|
||||
logger.V(4).Error(err, "Failed to getRoleNameAndArn")
|
||||
return hubClusterName, roleArn, err
|
||||
}
|
||||
|
||||
@@ -160,7 +162,6 @@ func createIAMRoleAndPolicy(ctx context.Context, hubClusterArn string, managedCl
|
||||
return hubClusterName, roleArn, err
|
||||
}
|
||||
|
||||
templateFiles := []string{"managed-cluster-policy/AccessPolicy.tmpl", "managed-cluster-policy/TrustPolicy.tmpl"}
|
||||
data := map[string]interface{}{
|
||||
"hubClusterArn": hubClusterArn,
|
||||
"managedClusterAccountId": managedClusterAccountId,
|
||||
@@ -169,9 +170,9 @@ func createIAMRoleAndPolicy(ctx context.Context, hubClusterArn string, managedCl
|
||||
"hubClusterName": hubClusterName,
|
||||
"managedClusterName": managedClusterName,
|
||||
}
|
||||
renderedTemplates, err := renderTemplates(templateFiles, data)
|
||||
trustPolicy, err := renderTemplate(trustPolicyTemplatePath, data)
|
||||
if err != nil {
|
||||
logger.V(4).Error(err, "Failed to render templates while creating IAM role and policy for ManagedCluster", "ManagedCluster", managedClusterName)
|
||||
logger.V(4).Error(err, "Failed to render template while creating IAM role and policy for ManagedCluster", "ManagedCluster", managedClusterName)
|
||||
return hubClusterName, roleArn, err
|
||||
}
|
||||
|
||||
@@ -184,7 +185,7 @@ func createIAMRoleAndPolicy(ctx context.Context, hubClusterArn string, managedCl
|
||||
|
||||
createRoleOutput, err = iamClient.CreateRole(ctx, &iam.CreateRoleInput{
|
||||
RoleName: aws.String(roleName),
|
||||
AssumeRolePolicyDocument: aws.String(renderedTemplates[1]),
|
||||
AssumeRolePolicyDocument: aws.String(trustPolicy),
|
||||
Tags: parsedTags,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -198,62 +199,29 @@ func createIAMRoleAndPolicy(ctx context.Context, hubClusterArn string, managedCl
|
||||
} else {
|
||||
logger.V(4).Info("Role created successfully for ManagedCluster", "IAMRole", *createRoleOutput.Role.Arn, "ManagedCluster", managedClusterName)
|
||||
}
|
||||
|
||||
createPolicyResult, err := iamClient.CreatePolicy(ctx, &iam.CreatePolicyInput{
|
||||
PolicyDocument: aws.String(renderedTemplates[0]),
|
||||
PolicyName: aws.String(policyName),
|
||||
})
|
||||
if err != nil {
|
||||
if !(strings.Contains(err.Error(), errEntityAlreadyExists)) {
|
||||
logger.V(4).Error(err, "Failed to create IAM Policy for ManagedCluster", "IAMPolicy", policyName, "ManagedCluster", managedClusterName)
|
||||
return hubClusterName, roleArn, err
|
||||
} else {
|
||||
logger.V(4).Info("Ignore IAM policy creation error for ManagedCluster as it already exists", "IAMPolicy", policyName, "ManagedCluster", managedClusterName)
|
||||
}
|
||||
} else {
|
||||
logger.V(4).Info("Policy created successfully for ManagedCluster", "IAMPolicy", *createPolicyResult.Policy.Arn, "ManagedCluster", managedClusterName)
|
||||
}
|
||||
|
||||
_, err = iamClient.AttachRolePolicy(ctx, &iam.AttachRolePolicyInput{
|
||||
PolicyArn: aws.String(policyArn),
|
||||
RoleName: aws.String(roleName),
|
||||
})
|
||||
if err != nil {
|
||||
logger.V(4).Error(err, "Unable to attach policy to role for ManagedCluster",
|
||||
"IAMPolicy", policyName, "IAMRole", roleName, "ManagedCluster", managedClusterName)
|
||||
return hubClusterName, roleArn, err
|
||||
} else {
|
||||
logger.V(4).Info("Successfully attached IAM Policy to Role for ManagedCluster",
|
||||
"IAMPolicy", policyName, "IAMRole", roleName, "ManagedCluster", managedClusterName)
|
||||
}
|
||||
}
|
||||
return hubClusterName, roleArn, nil
|
||||
}
|
||||
|
||||
func renderTemplates(argTemplates []string, data interface{}) (args []string, err error) {
|
||||
func renderTemplate(argTemplate string, data interface{}) (args string, err error) {
|
||||
var t *template.Template
|
||||
var filebytes []byte
|
||||
for _, arg := range argTemplates {
|
||||
filebytes, err = manifests.ManagedClusterPolicyManifestFiles.ReadFile(arg)
|
||||
if err != nil {
|
||||
args = nil
|
||||
return
|
||||
}
|
||||
contents := string(filebytes)
|
||||
t, err = template.New(contents).Parse(contents)
|
||||
if err != nil {
|
||||
args = nil
|
||||
return
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
err = t.Execute(buf, data)
|
||||
if err != nil {
|
||||
args = nil
|
||||
return
|
||||
}
|
||||
args = append(args, buf.String())
|
||||
filebytes, err = manifests.ManagedClusterPolicyManifestFiles.ReadFile(argTemplate)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
contents := string(filebytes)
|
||||
t, err = template.New(contents).Parse(contents)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
err = t.Execute(buf, data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
args = buf.String()
|
||||
|
||||
return
|
||||
}
|
||||
@@ -297,37 +265,12 @@ func createAccessEntry(ctx context.Context, eksClient *eks.Client, roleArn strin
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteIAMRoleAndPolicy(ctx context.Context, cfg aws.Config, roleName string, policyArn string) error {
|
||||
func deleteIAMRole(ctx context.Context, cfg aws.Config, roleName string) error {
|
||||
logger := klog.FromContext(ctx)
|
||||
|
||||
iamClient := iam.NewFromConfig(cfg)
|
||||
|
||||
_, err := iamClient.DetachRolePolicy(ctx, &iam.DetachRolePolicyInput{
|
||||
RoleName: &roleName,
|
||||
PolicyArn: &policyArn,
|
||||
})
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), errNoSuchEntity) {
|
||||
logger.V(4).Error(err, "Failed to detach Policy from Role", "Policy", policyArn, "Role", roleName)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
logger.V(4).Info("Policy detached successfully from Role", "Policy", policyArn, "Role", roleName)
|
||||
}
|
||||
|
||||
_, err = iamClient.DeletePolicy(ctx, &iam.DeletePolicyInput{
|
||||
PolicyArn: &policyArn,
|
||||
})
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), errNoSuchEntity) {
|
||||
logger.V(4).Error(err, "Failed to delete Policy", "Policy", policyArn)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
logger.V(4).Info("Policy deleted successfully", "Policy", policyArn)
|
||||
}
|
||||
|
||||
_, err = iamClient.DeleteRole(ctx, &iam.DeleteRoleInput{
|
||||
_, err := iamClient.DeleteRole(ctx, &iam.DeleteRoleInput{
|
||||
RoleName: &roleName,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -342,24 +285,22 @@ func deleteIAMRoleAndPolicy(ctx context.Context, cfg aws.Config, roleName string
|
||||
return nil
|
||||
}
|
||||
|
||||
func getRoleAndPolicyArn(ctx context.Context, managedCluster *v1.ManagedCluster, cfg aws.Config) (string, string, string, string, error) {
|
||||
func getRoleNameAndArn(ctx context.Context, managedCluster *v1.ManagedCluster, cfg aws.Config) (string, string, error) {
|
||||
logger := klog.FromContext(ctx)
|
||||
|
||||
managedClusterIamRoleSuffix :=
|
||||
managedCluster.Annotations["agent.open-cluster-management.io/managed-cluster-iam-role-suffix"]
|
||||
managedCluster.Annotations[operatorv1.ClusterAnnotationsKeyPrefix+"/"+ManagedClusterIAMRoleSuffix]
|
||||
|
||||
roleName := fmt.Sprintf("ocm-hub-%s", managedClusterIamRoleSuffix)
|
||||
policyName := roleName
|
||||
|
||||
creds, err := cfg.Credentials.Retrieve(ctx)
|
||||
if err != nil {
|
||||
logger.V(4).Error(err, "Failed to get IAM Credentials")
|
||||
return "", "", "", "", err
|
||||
return "", "", err
|
||||
}
|
||||
awsAccountId := creds.AccountID
|
||||
roleArn := fmt.Sprintf("arn:aws:iam::%s:role/%s", awsAccountId, roleName)
|
||||
policyArn := fmt.Sprintf("arn:aws:iam::%s:policy/%s", awsAccountId, policyName)
|
||||
return roleName, policyName, roleArn, policyArn, err
|
||||
return roleName, roleArn, err
|
||||
}
|
||||
|
||||
func deleteAccessEntry(ctx context.Context, eksClient *eks.Client, roleArn string, hubClusterName string) error {
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
clusterv1 "open-cluster-management.io/api/cluster/v1"
|
||||
operatorv1 "open-cluster-management.io/api/operator/v1"
|
||||
|
||||
"open-cluster-management.io/ocm/manifests"
|
||||
commonhelper "open-cluster-management.io/ocm/pkg/common/helpers"
|
||||
@@ -38,8 +39,8 @@ func TestAccept(t *testing.T) {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "managed-cluster1",
|
||||
Annotations: map[string]string{
|
||||
"agent.open-cluster-management.io/managed-cluster-arn": "arn:aws:eks:us-west-2:123456789012:cluster/managed-cluster1",
|
||||
"agent.open-cluster-management.io/managed-cluster-iam-role-suffix": "7f8141296c75f2871e3d030f85c35692",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterArn: "arn:aws:eks:us-west-2:123456789012:cluster/managed-cluster1",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterIAMRoleSuffix: "7f8141296c75f2871e3d030f85c35692",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -51,8 +52,8 @@ func TestAccept(t *testing.T) {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "managed-cluster2",
|
||||
Annotations: map[string]string{
|
||||
"agent.open-cluster-management.io/managed-cluster-arn": "arn:aws:eks:us-west-2:123456789012:cluster/managed-cluster2",
|
||||
"agent.open-cluster-management.io/managed-cluster-iam-role-suffix": "7f8141296c75f2871e3d030f85c35692",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterArn: "arn:aws:eks:us-west-2:123456789012:cluster/managed-cluster2",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterIAMRoleSuffix: "7f8141296c75f2871e3d030f85c35692",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -64,8 +65,8 @@ func TestAccept(t *testing.T) {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "managed-cluster3",
|
||||
Annotations: map[string]string{
|
||||
"agent.open-cluster-management.io/managed-cluster-arn": "arn:aws:eks:us-west-1:123456789012:cluster/managed-cluster3",
|
||||
"agent.open-cluster-management.io/managed-cluster-iam-role-suffix": "7f8141296c75f2871e3d030f85c35692",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterArn: "arn:aws:eks:us-west-1:123456789012:cluster/managed-cluster3",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterIAMRoleSuffix: "7f8141296c75f2871e3d030f85c35692",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -77,8 +78,8 @@ func TestAccept(t *testing.T) {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "managed-cluster4",
|
||||
Annotations: map[string]string{
|
||||
"agent.open-cluster-management.io/managed-cluster-arn": "arn:aws:eks:us-west-2:999999999999:cluster/managed-cluster4",
|
||||
"agent.open-cluster-management.io/managed-cluster-iam-role-suffix": "7f8141296c75f2871e3d030f85c35692",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterArn: "arn:aws:eks:us-west-2:999999999999:cluster/managed-cluster4",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterIAMRoleSuffix: "7f8141296c75f2871e3d030f85c35692",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -90,8 +91,8 @@ func TestAccept(t *testing.T) {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "managed-cluster5",
|
||||
Annotations: map[string]string{
|
||||
"agent.open-cluster-management.io/managed-cluster-arn": "XXXXXXarn:aws:eks:us-west-2:123456789012:cluster/managed-cluster5",
|
||||
"agent.open-cluster-management.io/managed-cluster-iam-role-suffix": "7f8141296c75f2871e3d030f85c35692",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterArn: "XXXXXXarn:aws:eks:us-west-2:123456789012:cluster/managed-cluster5",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterIAMRoleSuffix: "7f8141296c75f2871e3d030f85c35692",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -103,8 +104,8 @@ func TestAccept(t *testing.T) {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "managed-cluster6",
|
||||
Annotations: map[string]string{
|
||||
"agent.open-cluster-management.io/managed-cluster-arn": "",
|
||||
"agent.open-cluster-management.io/managed-cluster-iam-role-suffix": "7f8141296c75f2871e3d030f85c35692",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterArn: "",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterIAMRoleSuffix: "7f8141296c75f2871e3d030f85c35692",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -151,8 +152,7 @@ func TestNewDriverValidation(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenderTemplates(t *testing.T) {
|
||||
templateFiles := []string{"managed-cluster-policy/AccessPolicy.tmpl", "managed-cluster-policy/TrustPolicy.tmpl"}
|
||||
func TestRenderTemplate(t *testing.T) {
|
||||
data := map[string]interface{}{
|
||||
"hubClusterArn": "arn:aws:iam::123456789012:cluster/hub-cluster",
|
||||
"managedClusterAccountId": "123456789013",
|
||||
@@ -167,17 +167,9 @@ func TestRenderTemplates(t *testing.T) {
|
||||
data["managedClusterAccountId"].(string),
|
||||
data["managedClusterName"].(string),
|
||||
)
|
||||
renderedTemplates, _ := renderTemplates(templateFiles, data)
|
||||
trustPolicy, _ := renderTemplate(trustPolicyTemplatePath, data)
|
||||
|
||||
APfilebuf, APerr := manifests.ManagedClusterPolicyManifestFiles.ReadFile("managed-cluster-policy/AccessPolicy.tmpl")
|
||||
if APerr != nil {
|
||||
t.Errorf("Templates not rendered as expected")
|
||||
return
|
||||
}
|
||||
contents := string(APfilebuf)
|
||||
AccessPolicy := strings.Replace(contents, "{{.hubClusterArn}}", data["hubClusterArn"].(string), 1)
|
||||
|
||||
TPfilebuf, TPerr := manifests.ManagedClusterPolicyManifestFiles.ReadFile("managed-cluster-policy/TrustPolicy.tmpl")
|
||||
TPfilebuf, TPerr := manifests.ManagedClusterPolicyManifestFiles.ReadFile(trustPolicyTemplatePath)
|
||||
if TPerr != nil {
|
||||
t.Errorf("Templates not rendered as expected")
|
||||
return
|
||||
@@ -193,17 +185,7 @@ func TestRenderTemplates(t *testing.T) {
|
||||
|
||||
TrustPolicy := replacer.Replace(contentstrust)
|
||||
|
||||
if len(renderedTemplates) != 2 {
|
||||
t.Errorf("Templates not rendered as expected")
|
||||
return
|
||||
}
|
||||
|
||||
if renderedTemplates[0] != AccessPolicy {
|
||||
t.Errorf("AccessPolicy not rendered as expected")
|
||||
return
|
||||
}
|
||||
|
||||
if renderedTemplates[1] != TrustPolicy {
|
||||
if trustPolicy != TrustPolicy {
|
||||
t.Errorf("TrustPolicy not rendered as expected")
|
||||
return
|
||||
}
|
||||
@@ -223,20 +205,20 @@ func TestDeleteIAMRoleAndPolicy(t *testing.T) {
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "test delete IAM Role and policy",
|
||||
name: "test delete IAM Role",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
withAPIOptionsFunc: mockSuccessfulDeletionBehaviour,
|
||||
},
|
||||
managedClusterAnnotations: map[string]string{
|
||||
"agent.open-cluster-management.io/managed-cluster-iam-role-suffix": "960c4e56c25ba0b571ddcdaa7edc943e",
|
||||
"agent.open-cluster-management.io/managed-cluster-arn": "arn:aws:eks:us-west-2:123456789012:cluster/spoke-cluster",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterIAMRoleSuffix: "960c4e56c25ba0b571ddcdaa7edc943e",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterArn: "arn:aws:eks:us-west-2:123456789012:cluster/spoke-cluster",
|
||||
},
|
||||
want: nil,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "test delete IAM Role and policy with NoSuchEntity in DeleteRole",
|
||||
name: "test delete IAM Role with NoSuchEntity in DeleteRole",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
withAPIOptionsFunc: func(stack *middleware.Stack) error {
|
||||
@@ -247,73 +229,7 @@ func TestDeleteIAMRoleAndPolicy(t *testing.T) {
|
||||
|
||||
return stack.Finalize.Add(
|
||||
middleware.FinalizeMiddlewareFunc(
|
||||
"DeleteRoleOrDeletePolicyOrDetachPolicyMock3",
|
||||
func(ctx context.Context, input middleware.FinalizeInput, next middleware.FinalizeHandler) (middleware.FinalizeOutput, middleware.Metadata, error) {
|
||||
if middleware.GetOperationName(ctx) == "DetachRolePolicy" {
|
||||
return middleware.FinalizeOutput{
|
||||
Result: &iam.DetachRolePolicyOutput{},
|
||||
}, middleware.Metadata{}, fmt.Errorf("failed to detach IAM policy from role, NoSuchEntity")
|
||||
}
|
||||
return next.HandleFinalize(ctx, input)
|
||||
},
|
||||
),
|
||||
middleware.Before,
|
||||
)
|
||||
},
|
||||
},
|
||||
managedClusterAnnotations: map[string]string{
|
||||
"agent.open-cluster-management.io/managed-cluster-iam-role-suffix": "960c4e56c25ba0b571ddcdaa7edc943e",
|
||||
"agent.open-cluster-management.io/managed-cluster-arn": "arn:aws:eks:us-west-2:123456789012:cluster/spoke-cluster",
|
||||
},
|
||||
want: nil,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "test delete IAM Role and policy with NoSuchEntity in DeletePolicy",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
withAPIOptionsFunc: func(stack *middleware.Stack) error {
|
||||
err := mockSuccessfulDeletionBehaviour(stack)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return stack.Finalize.Add(
|
||||
middleware.FinalizeMiddlewareFunc(
|
||||
"DeleteRoleOrDeletePolicyOrDetachPolicyMock3",
|
||||
func(ctx context.Context, input middleware.FinalizeInput, next middleware.FinalizeHandler) (middleware.FinalizeOutput, middleware.Metadata, error) {
|
||||
if middleware.GetOperationName(ctx) == "DeletePolicy" {
|
||||
return middleware.FinalizeOutput{
|
||||
Result: nil,
|
||||
}, middleware.Metadata{}, fmt.Errorf("failed to delete IAM policy, NoSuchEntity")
|
||||
}
|
||||
return next.HandleFinalize(ctx, input)
|
||||
},
|
||||
),
|
||||
middleware.Before,
|
||||
)
|
||||
},
|
||||
},
|
||||
managedClusterAnnotations: map[string]string{
|
||||
"agent.open-cluster-management.io/managed-cluster-iam-role-suffix": "960c4e56c25ba0b571ddcdaa7edc943e",
|
||||
"agent.open-cluster-management.io/managed-cluster-arn": "arn:aws:eks:us-west-2:123456789012:cluster/spoke-cluster",
|
||||
},
|
||||
want: nil,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "test delete IAM Role and policy with NoSuchEntity in DeleteRole",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
withAPIOptionsFunc: func(stack *middleware.Stack) error {
|
||||
err := mockSuccessfulDeletionBehaviour(stack)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return stack.Finalize.Add(
|
||||
middleware.FinalizeMiddlewareFunc(
|
||||
"DeleteRoleOrDeletePolicyOrDetachPolicyMock3",
|
||||
"DeleteRoleMock3",
|
||||
func(ctx context.Context, input middleware.FinalizeInput, next middleware.FinalizeHandler) (middleware.FinalizeOutput, middleware.Metadata, error) {
|
||||
if middleware.GetOperationName(ctx) == "DeleteRole" {
|
||||
return middleware.FinalizeOutput{
|
||||
@@ -328,8 +244,8 @@ func TestDeleteIAMRoleAndPolicy(t *testing.T) {
|
||||
},
|
||||
},
|
||||
managedClusterAnnotations: map[string]string{
|
||||
"agent.open-cluster-management.io/managed-cluster-iam-role-suffix": "960c4e56c25ba0b571ddcdaa7edc943e",
|
||||
"agent.open-cluster-management.io/managed-cluster-arn": "arn:aws:eks:us-west-2:123456789012:cluster/spoke-cluster",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterIAMRoleSuffix: "960c4e56c25ba0b571ddcdaa7edc943e",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterArn: "arn:aws:eks:us-west-2:123456789012:cluster/spoke-cluster",
|
||||
},
|
||||
want: nil,
|
||||
wantErr: false,
|
||||
@@ -353,12 +269,12 @@ func TestDeleteIAMRoleAndPolicy(t *testing.T) {
|
||||
managedCluster := testinghelpers.NewManagedCluster()
|
||||
managedCluster.Annotations = tt.managedClusterAnnotations
|
||||
|
||||
roleName, _, _, policyArn, err := getRoleAndPolicyArn(tt.args.ctx, managedCluster, cfg)
|
||||
roleName, _, err := getRoleNameAndArn(tt.args.ctx, managedCluster, cfg)
|
||||
if err != nil {
|
||||
t.Errorf("Error getting role and policy Arn.")
|
||||
t.Errorf("Error getting role name")
|
||||
return
|
||||
}
|
||||
err = deleteIAMRoleAndPolicy(tt.args.ctx, cfg, roleName, policyArn)
|
||||
err = deleteIAMRole(tt.args.ctx, cfg, roleName)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("error = %#v, wantErr %#v", err, tt.wantErr)
|
||||
return
|
||||
@@ -546,8 +462,8 @@ func TestCleanup(t *testing.T) {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "managed-cluster",
|
||||
Annotations: map[string]string{
|
||||
"agent.open-cluster-management.io/managed-cluster-arn": "arn:aws:eks:us-west-2:123456789012:cluster/managed-cluster1",
|
||||
"agent.open-cluster-management.io/managed-cluster-iam-role-suffix": "7f8141296c75f2871e3d030f85c35692",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterArn: "arn:aws:eks:us-west-2:123456789012:cluster/managed-cluster1",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterIAMRoleSuffix: "7f8141296c75f2871e3d030f85c35692",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -588,7 +504,7 @@ func TestCleanup(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateIAMRoleAndPolicy(t *testing.T) {
|
||||
func TestCreateIAMRole(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
withAPIOptionsFunc func(*middleware.Stack) error
|
||||
@@ -602,13 +518,13 @@ func TestCreateIAMRoleAndPolicy(t *testing.T) {
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "test create IAM Role and policy",
|
||||
name: "test create IAM Role",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
withAPIOptionsFunc: func(stack *middleware.Stack) error {
|
||||
return stack.Finalize.Add(
|
||||
middleware.FinalizeMiddlewareFunc(
|
||||
"CreateRoleOrCreatePolicyOrAttachPolicyMock",
|
||||
"CreateRoleMock",
|
||||
func(ctx context.Context, input middleware.FinalizeInput, handler middleware.FinalizeHandler) (middleware.FinalizeOutput, middleware.Metadata, error) {
|
||||
operationName := middleware.GetOperationName(ctx)
|
||||
if operationName == "CreateRole" {
|
||||
@@ -620,20 +536,6 @@ func TestCreateIAMRoleAndPolicy(t *testing.T) {
|
||||
},
|
||||
}, middleware.Metadata{}, nil
|
||||
}
|
||||
if operationName == "CreatePolicy" {
|
||||
return middleware.FinalizeOutput{
|
||||
Result: &iam.CreatePolicyOutput{Policy: &iamtypes.Policy{
|
||||
PolicyName: aws.String("TestPolicy"),
|
||||
Arn: aws.String("arn:aws:iam::123456789012:role/TestPolicy"),
|
||||
},
|
||||
},
|
||||
}, middleware.Metadata{}, nil
|
||||
}
|
||||
if operationName == "AttachRolePolicy" {
|
||||
return middleware.FinalizeOutput{
|
||||
Result: &iam.AttachRolePolicyOutput{},
|
||||
}, middleware.Metadata{}, nil
|
||||
}
|
||||
return middleware.FinalizeOutput{}, middleware.Metadata{}, nil
|
||||
},
|
||||
),
|
||||
@@ -642,8 +544,8 @@ func TestCreateIAMRoleAndPolicy(t *testing.T) {
|
||||
},
|
||||
},
|
||||
managedClusterAnnotations: map[string]string{
|
||||
"agent.open-cluster-management.io/managed-cluster-iam-role-suffix": "960c4e56c25ba0b571ddcdaa7edc943e",
|
||||
"agent.open-cluster-management.io/managed-cluster-arn": "arn:aws:eks:us-west-2:123456789012:cluster/spoke-cluster",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterIAMRoleSuffix: "960c4e56c25ba0b571ddcdaa7edc943e",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterArn: "arn:aws:eks:us-west-2:123456789012:cluster/spoke-cluster",
|
||||
},
|
||||
want: nil,
|
||||
wantErr: false,
|
||||
@@ -667,20 +569,6 @@ func TestCreateIAMRoleAndPolicy(t *testing.T) {
|
||||
},
|
||||
}, middleware.Metadata{}, nil
|
||||
}
|
||||
if operationName == "CreatePolicy" {
|
||||
return middleware.FinalizeOutput{
|
||||
Result: &iam.CreatePolicyOutput{Policy: &iamtypes.Policy{
|
||||
PolicyName: aws.String("TestPolicy"),
|
||||
Arn: aws.String("arn:aws:iam::123456789012:role/TestPolicy"),
|
||||
},
|
||||
},
|
||||
}, middleware.Metadata{}, nil
|
||||
}
|
||||
if operationName == "AttachRolePolicy" {
|
||||
return middleware.FinalizeOutput{
|
||||
Result: &iam.AttachRolePolicyOutput{},
|
||||
}, middleware.Metadata{}, nil
|
||||
}
|
||||
return middleware.FinalizeOutput{}, middleware.Metadata{}, nil
|
||||
},
|
||||
),
|
||||
@@ -689,14 +577,14 @@ func TestCreateIAMRoleAndPolicy(t *testing.T) {
|
||||
},
|
||||
},
|
||||
managedClusterAnnotations: map[string]string{
|
||||
"agent.open-cluster-management.io/managed-cluster-iam-role-suffix": "test",
|
||||
"agent.open-cluster-management.io/managed-cluster-arn": "arn:aws:eks:us-west-2:123456789012:cluster/spoke-cluster",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterIAMRoleSuffix: "test",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterArn: "arn:aws:eks:us-west-2:123456789012:cluster/spoke-cluster",
|
||||
},
|
||||
want: fmt.Errorf("HubClusterARN provided during join by ManagedCluster spoke-cluster is different from the current hub cluster"),
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "test create IAM Role and policy with EntityAlreadyExists in CreateRole",
|
||||
name: "test create IAM Role with EntityAlreadyExists in CreateRole",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
withAPIOptionsFunc: func(stack *middleware.Stack) error {
|
||||
@@ -710,29 +598,6 @@ func TestCreateIAMRoleAndPolicy(t *testing.T) {
|
||||
Result: nil,
|
||||
}, middleware.Metadata{}, fmt.Errorf("failed to create IAM role, EntityAlreadyExists")
|
||||
}
|
||||
if operationName == "GetRole" {
|
||||
return middleware.FinalizeOutput{
|
||||
Result: &iam.GetRoleOutput{Role: &iamtypes.Role{
|
||||
RoleName: aws.String("TestRole"),
|
||||
Arn: aws.String("arn:aws:iam::123456789012:role/TestRole"),
|
||||
},
|
||||
},
|
||||
}, middleware.Metadata{}, nil
|
||||
}
|
||||
if operationName == "CreatePolicy" {
|
||||
return middleware.FinalizeOutput{
|
||||
Result: &iam.CreatePolicyOutput{Policy: &iamtypes.Policy{
|
||||
PolicyName: aws.String("TestPolicy"),
|
||||
Arn: aws.String("arn:aws:iam::123456789012:role/TestPolicy"),
|
||||
},
|
||||
},
|
||||
}, middleware.Metadata{}, nil
|
||||
}
|
||||
if operationName == "AttachRolePolicy" {
|
||||
return middleware.FinalizeOutput{
|
||||
Result: &iam.AttachRolePolicyOutput{},
|
||||
}, middleware.Metadata{}, nil
|
||||
}
|
||||
return middleware.FinalizeOutput{}, middleware.Metadata{}, nil
|
||||
},
|
||||
),
|
||||
@@ -741,14 +606,14 @@ func TestCreateIAMRoleAndPolicy(t *testing.T) {
|
||||
},
|
||||
},
|
||||
managedClusterAnnotations: map[string]string{
|
||||
"agent.open-cluster-management.io/managed-cluster-iam-role-suffix": "960c4e56c25ba0b571ddcdaa7edc943e",
|
||||
"agent.open-cluster-management.io/managed-cluster-arn": "arn:aws:eks:us-west-2:123456789012:cluster/spoke-cluster",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterIAMRoleSuffix: "960c4e56c25ba0b571ddcdaa7edc943e",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterArn: "arn:aws:eks:us-west-2:123456789012:cluster/spoke-cluster",
|
||||
},
|
||||
want: nil,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "test create IAM Role and policy with error in CreateRole",
|
||||
name: "test create IAM Role with error in CreateRole",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
withAPIOptionsFunc: func(stack *middleware.Stack) error {
|
||||
@@ -770,156 +635,12 @@ func TestCreateIAMRoleAndPolicy(t *testing.T) {
|
||||
},
|
||||
},
|
||||
managedClusterAnnotations: map[string]string{
|
||||
"agent.open-cluster-management.io/managed-cluster-iam-role-suffix": "960c4e56c25ba0b571ddcdaa7edc943e",
|
||||
"agent.open-cluster-management.io/managed-cluster-arn": "arn:aws:eks:us-west-2:123456789012:cluster/spoke-cluster",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterIAMRoleSuffix: "960c4e56c25ba0b571ddcdaa7edc943e",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterArn: "arn:aws:eks:us-west-2:123456789012:cluster/spoke-cluster",
|
||||
},
|
||||
want: fmt.Errorf("operation error IAM: CreateRole, failed to create IAM role"),
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "test create IAM Role and policy with EntityAlreadyExists in CreatePolicy",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
withAPIOptionsFunc: func(stack *middleware.Stack) error {
|
||||
return stack.Finalize.Add(
|
||||
middleware.FinalizeMiddlewareFunc(
|
||||
"CreatePolicyEntityAlreadyExistsMock",
|
||||
func(ctx context.Context, input middleware.FinalizeInput, handler middleware.FinalizeHandler) (middleware.FinalizeOutput, middleware.Metadata, error) {
|
||||
operationName := middleware.GetOperationName(ctx)
|
||||
if operationName == "CreateRole" {
|
||||
return middleware.FinalizeOutput{
|
||||
Result: &iam.CreateRoleOutput{Role: &iamtypes.Role{
|
||||
RoleName: aws.String("TestRole"),
|
||||
Arn: aws.String("arn:aws:iam::123456789012:role/TestRole"),
|
||||
},
|
||||
},
|
||||
}, middleware.Metadata{}, nil
|
||||
}
|
||||
if operationName == "CreatePolicy" {
|
||||
return middleware.FinalizeOutput{
|
||||
Result: nil,
|
||||
}, middleware.Metadata{}, fmt.Errorf("failed to create IAM policy, EntityAlreadyExists")
|
||||
}
|
||||
if operationName == "ListPolicies" {
|
||||
policies := []iamtypes.Policy{
|
||||
{
|
||||
PolicyName: aws.String("TestPolicy1"),
|
||||
Arn: aws.String("arn:aws:iam::123456789012:role/TestPolicy1"),
|
||||
},
|
||||
// You can add more policies here if needed
|
||||
{
|
||||
PolicyName: aws.String("ocm-hub-960c4e56c25ba0b571ddcdaa7edc943e"),
|
||||
Arn: aws.String("arn:aws:iam::123456789012:role/TestPolicy2"),
|
||||
},
|
||||
}
|
||||
return middleware.FinalizeOutput{
|
||||
Result: &iam.ListPoliciesOutput{Policies: policies},
|
||||
}, middleware.Metadata{}, nil
|
||||
}
|
||||
if operationName == "AttachRolePolicy" {
|
||||
return middleware.FinalizeOutput{
|
||||
Result: &iam.AttachRolePolicyOutput{},
|
||||
}, middleware.Metadata{}, nil
|
||||
}
|
||||
return middleware.FinalizeOutput{}, middleware.Metadata{}, nil
|
||||
},
|
||||
),
|
||||
middleware.Before,
|
||||
)
|
||||
},
|
||||
},
|
||||
managedClusterAnnotations: map[string]string{
|
||||
"agent.open-cluster-management.io/managed-cluster-iam-role-suffix": "960c4e56c25ba0b571ddcdaa7edc943e",
|
||||
"agent.open-cluster-management.io/managed-cluster-arn": "arn:aws:eks:us-west-2:123456789012:cluster/spoke-cluster",
|
||||
},
|
||||
want: nil,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "test create IAM Role and policy with error in CreatePolicy",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
withAPIOptionsFunc: func(stack *middleware.Stack) error {
|
||||
return stack.Finalize.Add(
|
||||
middleware.FinalizeMiddlewareFunc(
|
||||
"CreatePolicyErrorMock",
|
||||
func(ctx context.Context, input middleware.FinalizeInput, handler middleware.FinalizeHandler) (middleware.FinalizeOutput, middleware.Metadata, error) {
|
||||
operationName := middleware.GetOperationName(ctx)
|
||||
if operationName == "CreateRole" {
|
||||
return middleware.FinalizeOutput{
|
||||
Result: &iam.CreateRoleOutput{Role: &iamtypes.Role{
|
||||
RoleName: aws.String("TestRole"),
|
||||
Arn: aws.String("arn:aws:iam::123456789012:role/TestRole"),
|
||||
},
|
||||
},
|
||||
}, middleware.Metadata{}, nil
|
||||
}
|
||||
if operationName == "CreatePolicy" {
|
||||
return middleware.FinalizeOutput{
|
||||
Result: nil,
|
||||
}, middleware.Metadata{}, fmt.Errorf("failed to create IAM policy")
|
||||
}
|
||||
return middleware.FinalizeOutput{}, middleware.Metadata{}, nil
|
||||
},
|
||||
),
|
||||
middleware.Before,
|
||||
)
|
||||
},
|
||||
},
|
||||
managedClusterAnnotations: map[string]string{
|
||||
"agent.open-cluster-management.io/managed-cluster-iam-role-suffix": "960c4e56c25ba0b571ddcdaa7edc943e",
|
||||
"agent.open-cluster-management.io/managed-cluster-arn": "arn:aws:eks:us-west-2:123456789012:cluster/spoke-cluster",
|
||||
},
|
||||
want: fmt.Errorf("operation error IAM: CreatePolicy, failed to create IAM policy"),
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "test create IAM Role and policy with error in AttachRolePolicy",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
withAPIOptionsFunc: func(stack *middleware.Stack) error {
|
||||
return stack.Finalize.Add(
|
||||
middleware.FinalizeMiddlewareFunc(
|
||||
"AttachRolePolicyErrorMock",
|
||||
func(ctx context.Context, input middleware.FinalizeInput, handler middleware.FinalizeHandler) (middleware.FinalizeOutput, middleware.Metadata, error) {
|
||||
operationName := middleware.GetOperationName(ctx)
|
||||
if operationName == "CreateRole" {
|
||||
return middleware.FinalizeOutput{
|
||||
Result: &iam.CreateRoleOutput{Role: &iamtypes.Role{
|
||||
RoleName: aws.String("TestRole"),
|
||||
Arn: aws.String("arn:aws:iam::123456789012:role/TestRole"),
|
||||
},
|
||||
},
|
||||
}, middleware.Metadata{}, nil
|
||||
}
|
||||
if operationName == "CreatePolicy" {
|
||||
return middleware.FinalizeOutput{
|
||||
Result: &iam.CreatePolicyOutput{Policy: &iamtypes.Policy{
|
||||
PolicyName: aws.String("TestPolicy"),
|
||||
Arn: aws.String("arn:aws:iam::123456789012:role/TestPolicy"),
|
||||
},
|
||||
},
|
||||
}, middleware.Metadata{}, nil
|
||||
}
|
||||
if operationName == "AttachRolePolicy" {
|
||||
return middleware.FinalizeOutput{
|
||||
Result: nil,
|
||||
}, middleware.Metadata{}, fmt.Errorf("failed to attach policy to role")
|
||||
}
|
||||
return middleware.FinalizeOutput{}, middleware.Metadata{}, nil
|
||||
},
|
||||
),
|
||||
middleware.Before,
|
||||
)
|
||||
},
|
||||
},
|
||||
managedClusterAnnotations: map[string]string{
|
||||
"agent.open-cluster-management.io/managed-cluster-iam-role-suffix": "960c4e56c25ba0b571ddcdaa7edc943e",
|
||||
"agent.open-cluster-management.io/managed-cluster-arn": "arn:aws:eks:us-west-2:123456789012:cluster/spoke-cluster",
|
||||
},
|
||||
want: fmt.Errorf("operation error IAM: AttachRolePolicy, failed to attach policy to role"),
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range cases {
|
||||
@@ -993,8 +714,8 @@ func TestCreateAccessEntries(t *testing.T) {
|
||||
},
|
||||
},
|
||||
managedClusterAnnotations: map[string]string{
|
||||
"agent.open-cluster-management.io/managed-cluster-iam-role-suffix": "960c4e56c25ba0b571ddcdaa7edc943e",
|
||||
"agent.open-cluster-management.io/managed-cluster-arn": "arn:aws:eks:us-west-2:123456789012:cluster/spoke-cluster",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterIAMRoleSuffix: "960c4e56c25ba0b571ddcdaa7edc943e",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterArn: "arn:aws:eks:us-west-2:123456789012:cluster/spoke-cluster",
|
||||
},
|
||||
want: nil,
|
||||
wantErr: false,
|
||||
@@ -1022,8 +743,8 @@ func TestCreateAccessEntries(t *testing.T) {
|
||||
},
|
||||
},
|
||||
managedClusterAnnotations: map[string]string{
|
||||
"agent.open-cluster-management.io/managed-cluster-iam-role-suffix": "960c4e56c25ba0b571ddcdaa7edc943e",
|
||||
"agent.open-cluster-management.io/managed-cluster-arn": "arn:aws:eks:us-west-2:123456789012:cluster/spoke-cluster",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterIAMRoleSuffix: "960c4e56c25ba0b571ddcdaa7edc943e",
|
||||
operatorv1.ClusterAnnotationsKeyPrefix + "/" + ManagedClusterArn: "arn:aws:eks:us-west-2:123456789012:cluster/spoke-cluster",
|
||||
},
|
||||
want: fmt.Errorf("operation error EKS: CreateAccessEntry, failed to create access entry"),
|
||||
wantErr: true,
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
ocmfeature "open-cluster-management.io/api/feature"
|
||||
|
||||
commonhelpers "open-cluster-management.io/ocm/pkg/common/helpers"
|
||||
"open-cluster-management.io/ocm/pkg/features"
|
||||
"open-cluster-management.io/ocm/pkg/registration/helpers"
|
||||
)
|
||||
@@ -119,7 +120,7 @@ func (o *SpokeAgentOptions) Validate() error {
|
||||
return errors.New("client certificate expiration seconds must greater or qual to 3600")
|
||||
}
|
||||
|
||||
if (o.RegistrationAuth == AwsIrsaAuthType) && (o.HubClusterArn == "") {
|
||||
if (o.RegistrationAuth == commonhelpers.AwsIrsaAuthType) && (o.HubClusterArn == "") {
|
||||
return errors.New("EksHubClusterArn cannot be empty if RegistrationAuth is awsirsa")
|
||||
}
|
||||
|
||||
|
||||
@@ -43,8 +43,6 @@ import (
|
||||
// TODO if we register the lease informer to the lease controller, we need to increase this time
|
||||
var AddOnLeaseControllerSyncInterval = 30 * time.Second
|
||||
|
||||
const AwsIrsaAuthType = "awsirsa"
|
||||
|
||||
type SpokeAgentConfig struct {
|
||||
agentOptions *commonoptions.AgentOptions
|
||||
registrationOption *SpokeAgentOptions
|
||||
@@ -190,7 +188,7 @@ func (o *SpokeAgentConfig) RunSpokeAgentWithSpokeInformers(ctx context.Context,
|
||||
|
||||
// initiate registration driver
|
||||
var registerDriver register.RegisterDriver
|
||||
if o.registrationOption.RegistrationAuth == AwsIrsaAuthType {
|
||||
if o.registrationOption.RegistrationAuth == helpers.AwsIrsaAuthType {
|
||||
registerDriver = awsIrsa.NewAWSIRSADriver(o.registrationOption.ManagedClusterArn,
|
||||
o.registrationOption.ManagedClusterRoleSuffix,
|
||||
o.registrationOption.HubClusterArn,
|
||||
@@ -570,7 +568,7 @@ func (o *SpokeAgentConfig) newRestirationAuthOption(
|
||||
clusterInformers clusterv1informers.SharedInformerFactory,
|
||||
clusterClient clusterv1client.Interface,
|
||||
) (any, error) {
|
||||
if o.registrationOption.RegistrationAuth == AwsIrsaAuthType {
|
||||
if o.registrationOption.RegistrationAuth == helpers.AwsIrsaAuthType {
|
||||
if o.registrationOption.HubClusterArn != "" {
|
||||
return awsIrsa.NewAWSOption(
|
||||
secretOption,
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
|
||||
ocmfeature "open-cluster-management.io/api/feature"
|
||||
|
||||
commonhelpers "open-cluster-management.io/ocm/pkg/common/helpers"
|
||||
commonoptions "open-cluster-management.io/ocm/pkg/common/options"
|
||||
testingcommon "open-cluster-management.io/ocm/pkg/common/testing"
|
||||
"open-cluster-management.io/ocm/pkg/features"
|
||||
@@ -46,7 +47,7 @@ func TestValidate(t *testing.T) {
|
||||
defaultCompletedOptions := NewSpokeAgentOptions()
|
||||
defaultCompletedOptions.BootstrapKubeconfig = "/spoke/bootstrap/kubeconfig"
|
||||
awsCompletedOptionsHubArnMissing := *defaultCompletedOptions
|
||||
awsCompletedOptionsHubArnMissing.RegistrationAuth = AwsIrsaAuthType
|
||||
awsCompletedOptionsHubArnMissing.RegistrationAuth = commonhelpers.AwsIrsaAuthType
|
||||
awsDefaultCompletedOptions := awsCompletedOptionsHubArnMissing
|
||||
awsDefaultCompletedOptions.HubClusterArn = "arn:aws:eks:us-west-2:123456789012:cluster/hub-cluster1"
|
||||
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
# Manually join Hub and Spoke using AWS-based authentication
|
||||
|
||||
This guide provides list of manual steps on how we can manually join AWS EKS clusters as Hub and Spoke using OCM.
|
||||
This guide provides list of steps to join AWS EKS clusters as Hub and Spoke using OCM.
|
||||
|
||||
# Background
|
||||
|
||||
We are working on a new feature to run OCM natively on EKS with AWS IAM based authentication. More details, on why and how, can be found in [enhancement proposal](https://github.com/open-cluster-management-io/enhancements/blob/main/enhancements/sig-architecture/105-aws-iam-registration/README.md). The purpose of this document is to:
|
||||
- Share with community, the proof of design proposed in [enhancement proposal](https://github.com/open-cluster-management-io/enhancements/blob/main/enhancements/sig-architecture/105-aws-iam-registration/README.md)
|
||||
- Get early feedback
|
||||
- Share our progress on the implementation
|
||||
|
||||
This feature allows you to run OCM natively on EKS with AWS IAM based authentication. More details, on why and how, can be found in [enhancement proposal](https://github.com/open-cluster-management-io/enhancements/blob/main/enhancements/sig-architecture/105-aws-iam-registration/README.md).
|
||||
|
||||
> **Note:**
|
||||
>
|
||||
> This solution uses [AWS IRSA](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html) for out going authentication from within an EKS cluster to AWS, and [EKS access entries](https://docs.aws.amazon.com/eks/latest/userguide/access-entries.html) for incoming authentication from outside world to inside the EKS cluster.
|
||||
|
||||
While the implementation of this feature is in progress, in the hub and spoke side components, the hub and spoke can be joined using AWS IAM based authentication by running following steps to manipulate hub and spoke components manually:
|
||||
The hub and spoke can be joined using AWS IAM based authentication by running following steps:
|
||||
|
||||
1. Login to hub and spoke clusters in 2 separate shell sessions with admin access to aws as well as EKS cluster and set following env vars in both.
|
||||
> **Note:** The md5 hash is generated as described [here](https://github.com/open-cluster-management-io/enhancements/blob/main/enhancements/sig-architecture/105-aws-iam-registration/README.md?plain=1#L249). [This](https://www.md5hashgenerator.com/) website can be used to generate md5 hash for these steps.
|
||||
@@ -25,8 +21,10 @@ While the implementation of this feature is in progress, in the hub and spoke si
|
||||
export SPOKE_ACCOUNT_ID=<spoke-cluster-account-id>
|
||||
export HUB_ROLE_NAME=ocm-hub-<md5hash>
|
||||
export SPOKE_ROLE_NAME=ocm-managed-cluster-<md5hash>
|
||||
export HUB_POLICY_NAME=<IAM-policy-created-on-hub-IAM-for-spoke>
|
||||
export IDENTITY_CREATOR_ROLE_NAME=<hub-cluster-name>_managed-cluster-identity-creator
|
||||
export HUB_POLICY_NAME=<IAM-policy-created-on-hub-IAM-for-hub>
|
||||
export SPOKE_POLICY_NAME=<IAM-policy-created-on-spoke-IAM-for-spoke>
|
||||
export HUB_OIDC_PROVIDER_ID=<spoke-cluster-AWS-oidc-provider>
|
||||
export SPOKE_OIDC_PROVIDER_ID=<spoke-cluster-AWS-oidc-provider>
|
||||
export HUB_REGION=<hub-cluster-region>
|
||||
export SPOKE_REGION=<spoke-cluster-region>
|
||||
@@ -40,14 +38,16 @@ While the implementation of this feature is in progress, in the hub and spoke si
|
||||
export SPOKE_ACCOUNT_ID=567890123456
|
||||
export HUB_ROLE_NAME=ocm-hub-138c525cf3b7f74ba3b945e7847792cc
|
||||
export SPOKE_ROLE_NAME=ocm-managed-cluster-138c525cf3b7f74ba3b945e7847792cc
|
||||
export IDENTITY_CREATOR_ROLE_NAME=hub_managed-cluster-identity-creator
|
||||
export HUB_POLICY_NAME=hub
|
||||
export SPOKE_POLICY_NAME=spoke
|
||||
export HUB_OIDC_PROVIDER_ID=AE6D831CFA22823093D17E608EE0048C
|
||||
export SPOKE_OIDC_PROVIDER_ID=BE6D831CFA22823093D17E608EE0048C
|
||||
export HUB_REGION=us-west-2
|
||||
export SPOKE_REGION=us-west-2
|
||||
```
|
||||
|
||||
2. Login to spoke AWS account and create IAM role, policy and tags on spoke IAM. Go to the folder containing this markdown file in this [repository](https://github.com/open-cluster-management-io/ocm/tree/main/solutions/joining-hub-and-spoke-with-aws-auth-manually) and run following commands:
|
||||
2. Login to spoke AWS account and create prerequisite IAM role, policy and tags on spoke IAM. Go to the folder containing this markdown file in this [repository](https://github.com/open-cluster-management-io/ocm/tree/main/solutions/joining-hub-and-spoke-with-aws-auth-manually) and run following commands:
|
||||
```bash
|
||||
sed -e "s/PROVIDER_ID/$SPOKE_OIDC_PROVIDER_ID/g" -e "s/ACCOUNT_ID/$SPOKE_ACCOUNT_ID/g" -e "s/REGION/$SPOKE_REGION/g" templates/Template-Spoke-Role-Trust-Policy.json > templates/Spoke-Role-Trust-Policy.json
|
||||
aws iam create-role --role-name $SPOKE_ROLE_NAME --assume-role-policy-document file://templates/Spoke-Role-Trust-Policy.json
|
||||
@@ -58,9 +58,20 @@ While the implementation of this feature is in progress, in the hub and spoke si
|
||||
aws iam tag-role --role-name $SPOKE_ROLE_NAME --tags '[{"Key":"hub_cluster_account_id", "Value":"'$HUB_ACCOUNT_ID'"},{"Key":"hub_cluster_name", "Value":"'$HUB_CLUSTER_NAME'"},{"Key":"managed_cluster_account_id", "Value":"'$SPOKE_ACCOUNT_ID'"},{"Key":"managed_cluster_name", "Value":"'$SPOKE_CLUSTER_NAME'"}]'
|
||||
```
|
||||
|
||||
3. Login to hub EKS clusters and initialize hub:
|
||||
3. Login into hub aws account and create identity-creator hub role using following script:
|
||||
```shell
|
||||
clusteradm init --wait
|
||||
sed -e "s/HUB_ACCOUNT_ID/$HUB_ACCOUNT_ID/g" -e "s/HUB_REGION/$HUB_REGION/g" -e "s/HUB_OIDC_PROVIDER_ID/$HUB_OIDC_PROVIDER_ID/g" templates/Template-Identity-Creator-Trust-Policy.json > templates/Identity-Creator-Trust-Policy.json
|
||||
aws iam create-role --role-name $IDENTITY_CREATOR_ROLE_NAME --assume-role-policy-document file://templates/Identity-Creator-Trust-Policy.json
|
||||
|
||||
sed -e "s/HUB_ACCOUNT_ID/$HUB_ACCOUNT_ID/g" -e "s/HUB_REGION/$HUB_REGION/g" templates/Template-Identity-Creator-Permission-Policy.json > templates/Identity-Creator-Permission-Policy.json
|
||||
aws iam put-role-policy --role-name $IDENTITY_CREATOR_ROLE_NAME --policy-name $HUB_POLICY_NAME --policy-document file://templates/Identity-Creator-Permission-Policy.json
|
||||
```
|
||||
|
||||
4. Login to hub EKS clusters and initialize hub:
|
||||
```shell
|
||||
clusteradm init --bundle-version latest --registration-drivers awsirsa \
|
||||
--feature-gates ManagedClusterAutoApproval=true \
|
||||
--auto-approved-arn-patterns "arn:aws:eks:us-west-2:123412341234:cluster/.*" --wait
|
||||
|
||||
# export hub apiserver url and token from the output of above command
|
||||
# it will be used by spoke
|
||||
@@ -68,88 +79,17 @@ While the implementation of this feature is in progress, in the hub and spoke si
|
||||
export HUB_API_SERVER="https://C66946AA519C4818E2189CE5A9324551.wk7.us-west-2.eks.amazonaws.com"
|
||||
```
|
||||
|
||||
4. Login to spoke EKS clusters and join with hub, note the new command line options on second line:
|
||||
5. Login to spoke EKS clusters and join with hub, note the new command line options on second line:
|
||||
```shell
|
||||
clusteradm join --hub-token $TOKEN --hub-apiserver $HUB_API_SERVER --wait --cluster-name $SPOKE_CLUSTER_NAME --singleton \
|
||||
--bundle-version latest --registration-auth awsirsa --hub-cluster-arn arn:aws:eks:$HUB_REGION:"$HUB_ACCOUNT_ID":cluster/$HUB_CLUSTER_NAME
|
||||
clusteradm join --hub-token $TOKEN --hub-apiserver $HUB_API_SERVER \
|
||||
--wait --cluster-name $SPOKE_CLUSTER_NAME --singleton \
|
||||
--bundle-version latest --registration-auth awsirsa \
|
||||
--hub-cluster-arn arn:aws:eks:$HUB_REGION:"$HUB_ACCOUNT_ID":cluster/$HUB_CLUSTER_NAME
|
||||
```
|
||||
|
||||
5. Making aws-cli available in klusterlet-agent:
|
||||
```shell
|
||||
# Scaling down klusterlet operator
|
||||
kubectl -n open-cluster-management patch deployment klusterlet --type='json' -p='[{"op": "replace", "path": "/spec/replicas", "value":0}]'
|
||||
|
||||
# Prepare klusterlet-agent to host aws-cli
|
||||
# Adds initContainer to klusterlet-agent deployment
|
||||
# Add aws-cli to PATH
|
||||
|
||||
kubectl -n open-cluster-management-agent patch deployment klusterlet-agent --type='json' -p='[
|
||||
{
|
||||
"op": "add",
|
||||
"path": "/spec/template/spec/volumes/-",
|
||||
"value": {
|
||||
"name": "awscli",
|
||||
"emptyDir": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"op": "add",
|
||||
"path": "/spec/template/spec/containers/0/volumeMounts/-",
|
||||
"value": {
|
||||
"name": "awscli",
|
||||
"mountPath": "/awscli"
|
||||
}
|
||||
},
|
||||
{
|
||||
"op": "add",
|
||||
"path": "/spec/template/spec/initContainers",
|
||||
"value": [
|
||||
{
|
||||
"name": "load-awscli",
|
||||
"image": "amazon/aws-cli:latest",
|
||||
"command": ["cp", "-vr", "/usr/local/aws-cli/v2/current/dist", "/awscli"],
|
||||
"volumeMounts": [
|
||||
{
|
||||
"name": "awscli",
|
||||
"mountPath": "/awscli"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"op": "add",
|
||||
"path": "/spec/template/spec/containers/0/env/-",
|
||||
"value": {
|
||||
"name": "PATH",
|
||||
"value": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/awscli/dist"
|
||||
}
|
||||
}
|
||||
]'
|
||||
|
||||
```
|
||||
|
||||
6. Login into hub aws account and create hub role using following script:
|
||||
```shell
|
||||
sed -e "s/ROLE_NAME/$SPOKE_ROLE_NAME/g" -e "s/SPOKE_ACCOUNT_ID/$SPOKE_ACCOUNT_ID/g" -e "s/HUB_ACCOUNT_ID/$HUB_ACCOUNT_ID/g" -e "s/HUB_CLUSTER_NAME/$HUB_CLUSTER_NAME/g" -e "s/SPOKE_CLUSTER_NAME/$SPOKE_CLUSTER_NAME/g" templates/Template-Hub-Role-Trust-Policy.json > templates/Hub-Role-Trust-Policy.json
|
||||
aws iam create-role --role-name $HUB_ROLE_NAME --assume-role-policy-document file://templates/Hub-Role-Trust-Policy.json
|
||||
|
||||
sed -e "s/REGION/$HUB_REGION/g" -e "s/ACCOUNT_ID/$HUB_ACCOUNT_ID/g" -e "s/CLUSTER_NAME/$HUB_CLUSTER_NAME/g" templates/Template-Hub-Role-Permission-Policy.json > templates/Hub-Role-Permission-Policy.json
|
||||
aws iam put-role-policy --role-name $HUB_ROLE_NAME --policy-name $HUB_POLICY_NAME --policy-document file://templates/Hub-Role-Permission-Policy.json
|
||||
```
|
||||
|
||||
7. Accept the ManagedCluster registration request on hub cluster:
|
||||
6. Accept the ManagedCluster registration request on hub cluster:
|
||||
```shell
|
||||
clusteradm accept --cluster $SPOKE_CLUSTER_NAME
|
||||
```
|
||||
> Note: Ignore the following error as there is no CSR in aws registration flow:
|
||||
>
|
||||
> Error: no csr is approved yet for cluster `spoke-cluster-name`
|
||||
|
||||
8. Create access entry on hub EKS cluster using the below commands:
|
||||
```shell
|
||||
aws eks list-access-entries --cluster $HUB_CLUSTER_NAME --region=$HUB_REGION
|
||||
aws eks create-access-entry --cluster-name $HUB_CLUSTER_NAME --region=$HUB_REGION --principal-arn arn:aws:iam::"$HUB_ACCOUNT_ID":role/$HUB_ROLE_NAME --username $SPOKE_CLUSTER_NAME --kubernetes-groups open-cluster-management:$SPOKE_CLUSTER_NAME
|
||||
aws eks list-access-entries --cluster $HUB_CLUSTER_NAME --region=$HUB_REGION | grep -i $HUB_ROLE_NAME
|
||||
```
|
||||
9. Create a sample manifestwork in hub. Confirm that resources are pushed to spoke.
|
||||
7. Create a sample manifestwork in hub. Confirm that resources are pushed to spoke.
|
||||
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"eks:DescribeCluster",
|
||||
"eks:ListClusters"
|
||||
],
|
||||
"Resource": "arn:aws:eks:REGION:ACCOUNT_ID:cluster/CLUSTER_NAME"
|
||||
}
|
||||
]
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"iam:CreateRole",
|
||||
"eks:CreateAccessEntry",
|
||||
"iam:DeleteRole",
|
||||
"eks:DeleteAccessEntry",
|
||||
"iam:TagRole",
|
||||
"eks:TagResource"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:iam::HUB_ACCOUNT_ID:role/ocm-hub-*",
|
||||
"arn:aws:iam::HUB_ACCOUNT_ID:policy/ocm-hub-*",
|
||||
"arn:aws:eks:HUB_REGION:HUB_ACCOUNT_ID:cluster/*",
|
||||
"arn:aws:eks:HUB_REGION:HUB_ACCOUNT_ID:access-entry/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Federated": "arn:aws:iam::HUB_ACCOUNT_ID:oidc-provider/oidc.eks.HUB_REGION.amazonaws.com/id/HUB_OIDC_PROVIDER_ID"
|
||||
},
|
||||
"Action": "sts:AssumeRoleWithWebIdentity",
|
||||
"Condition": {
|
||||
"StringEquals": {
|
||||
"oidc.eks.HUB_REGION.amazonaws.com/id/HUB_OIDC_PROVIDER_ID:aud": "sts.amazonaws.com",
|
||||
"oidc.eks.HUB_REGION.amazonaws.com/id/HUB_OIDC_PROVIDER_ID:sub": "system:serviceaccount:open-cluster-management-hub:registration-controller-sa"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
operatorapiv1 "open-cluster-management.io/api/operator/v1"
|
||||
|
||||
"open-cluster-management.io/ocm/pkg/common/helpers"
|
||||
)
|
||||
|
||||
var _ = ginkgo.Describe("ClusterManager Default Mode with aws registration", func() {
|
||||
@@ -46,7 +48,7 @@ var _ = ginkgo.Describe("ClusterManager Default Mode with aws registration", fun
|
||||
clusterManager.Spec.RegistrationConfiguration = &operatorapiv1.RegistrationHubConfiguration{}
|
||||
clusterManager.Spec.RegistrationConfiguration.RegistrationDrivers = []operatorapiv1.RegistrationDriverHub{
|
||||
{
|
||||
AuthType: "awsirsa",
|
||||
AuthType: helpers.AwsIrsaAuthType,
|
||||
AwsIrsa: &operatorapiv1.AwsIrsaConfig{
|
||||
HubClusterArn: hubClusterArn,
|
||||
Tags: []string{
|
||||
@@ -143,7 +145,7 @@ var _ = ginkgo.Describe("ClusterManager Default Mode with aws registration", fun
|
||||
clusterManager.Spec.RegistrationConfiguration = &operatorapiv1.RegistrationHubConfiguration{}
|
||||
clusterManager.Spec.RegistrationConfiguration.RegistrationDrivers = []operatorapiv1.RegistrationDriverHub{
|
||||
{
|
||||
AuthType: "awsirsa",
|
||||
AuthType: helpers.AwsIrsaAuthType,
|
||||
AwsIrsa: &operatorapiv1.AwsIrsaConfig{
|
||||
HubClusterArn: hubClusterArn,
|
||||
},
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
|
||||
operatorapiv1 "open-cluster-management.io/api/operator/v1"
|
||||
|
||||
commonhelpers "open-cluster-management.io/ocm/pkg/common/helpers"
|
||||
"open-cluster-management.io/ocm/pkg/operator/helpers"
|
||||
"open-cluster-management.io/ocm/pkg/registration/spoke"
|
||||
"open-cluster-management.io/ocm/test/integration/util"
|
||||
)
|
||||
|
||||
@@ -57,7 +57,7 @@ var _ = ginkgo.Describe("Klusterlet using aws auth", func() {
|
||||
Namespace: klusterletNamespace,
|
||||
RegistrationConfiguration: &operatorapiv1.RegistrationConfiguration{
|
||||
RegistrationDriver: operatorapiv1.RegistrationDriver{
|
||||
AuthType: spoke.AwsIrsaAuthType,
|
||||
AuthType: commonhelpers.AwsIrsaAuthType,
|
||||
AwsIrsa: &operatorapiv1.AwsIrsa{
|
||||
HubClusterArn: util.HubClusterArn,
|
||||
ManagedClusterArn: util.ManagedClusterArn,
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
|
||||
operatorapiv1 "open-cluster-management.io/api/operator/v1"
|
||||
|
||||
commonhelpers "open-cluster-management.io/ocm/pkg/common/helpers"
|
||||
"open-cluster-management.io/ocm/pkg/operator/helpers"
|
||||
"open-cluster-management.io/ocm/pkg/registration/spoke"
|
||||
"open-cluster-management.io/ocm/test/integration/util"
|
||||
)
|
||||
|
||||
@@ -44,7 +44,7 @@ var _ = ginkgo.Describe("Klusterlet Singleton mode with aws auth", func() {
|
||||
},
|
||||
RegistrationConfiguration: &operatorapiv1.RegistrationConfiguration{
|
||||
RegistrationDriver: operatorapiv1.RegistrationDriver{
|
||||
AuthType: spoke.AwsIrsaAuthType,
|
||||
AuthType: commonhelpers.AwsIrsaAuthType,
|
||||
AwsIrsa: &operatorapiv1.AwsIrsa{
|
||||
HubClusterArn: util.HubClusterArn,
|
||||
ManagedClusterArn: util.ManagedClusterArn,
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
operatorv1 "open-cluster-management.io/api/operator/v1"
|
||||
|
||||
commonhelpers "open-cluster-management.io/ocm/pkg/common/helpers"
|
||||
commonoptions "open-cluster-management.io/ocm/pkg/common/options"
|
||||
"open-cluster-management.io/ocm/pkg/registration/register/aws_irsa"
|
||||
"open-cluster-management.io/ocm/pkg/registration/spoke"
|
||||
@@ -27,7 +28,7 @@ var _ = ginkgo.Describe("Cluster Annotations for aws", func() {
|
||||
managedClusterRoleSuffix := "7f8141296c75f2871e3d030f85c35692"
|
||||
hubClusterArn := "arn:aws:eks:us-west-2:123456789012:cluster/hub-cluster1"
|
||||
agentOptions := &spoke.SpokeAgentOptions{
|
||||
RegistrationAuth: spoke.AwsIrsaAuthType,
|
||||
RegistrationAuth: commonhelpers.AwsIrsaAuthType,
|
||||
HubClusterArn: hubClusterArn,
|
||||
ManagedClusterArn: managedClusterArn,
|
||||
ManagedClusterRoleSuffix: managedClusterRoleSuffix,
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
clusterv1 "open-cluster-management.io/api/cluster/v1"
|
||||
ocmfeature "open-cluster-management.io/api/feature"
|
||||
|
||||
"open-cluster-management.io/ocm/pkg/common/helpers"
|
||||
commonoptions "open-cluster-management.io/ocm/pkg/common/options"
|
||||
"open-cluster-management.io/ocm/pkg/features"
|
||||
"open-cluster-management.io/ocm/pkg/registration/hub"
|
||||
@@ -210,7 +211,7 @@ var _ = ginkgo.BeforeSuite(func() {
|
||||
defer ginkgo.GinkgoRecover()
|
||||
m := hub.NewHubManagerOptions()
|
||||
m.ImportOption.APIServerURL = cfg.Host
|
||||
m.EnabledRegistrationDrivers = []string{"csr", "awsirsa"}
|
||||
m.EnabledRegistrationDrivers = []string{helpers.CSRAuthType, helpers.AwsIrsaAuthType}
|
||||
m.HubClusterArn = "arn:aws:eks:us-west-2:123456789012:cluster/hub-cluster1"
|
||||
m.ClusterAutoApprovalUsers = []string{util.AutoApprovalBootstrapUser}
|
||||
m.AutoApprovedARNPatterns = []string{"arn:aws:eks:us-west-2:123456789012:cluster/.*"}
|
||||
|
||||
@@ -42,7 +42,7 @@ var _ = ginkgo.Describe("Joining Process for aws flow", func() {
|
||||
|
||||
// run registration agent
|
||||
agentOptions := &spoke.SpokeAgentOptions{
|
||||
RegistrationAuth: spoke.AwsIrsaAuthType,
|
||||
RegistrationAuth: helpers.AwsIrsaAuthType,
|
||||
HubClusterArn: hubClusterArn,
|
||||
ManagedClusterArn: managedClusterArn,
|
||||
ManagedClusterRoleSuffix: managedClusterRoleSuffix,
|
||||
@@ -107,10 +107,10 @@ var _ = ginkgo.Describe("Joining Process for aws flow", func() {
|
||||
return fmt.Errorf("user pointed to by the current-context is missing")
|
||||
}
|
||||
if hubUser.Exec.APIVersion != "client.authentication.k8s.io/v1beta1" {
|
||||
return fmt.Errorf("user exec plugun apiVersion is invalid")
|
||||
return fmt.Errorf("user exec plugin apiVersion is invalid")
|
||||
}
|
||||
if hubUser.Exec.Command != "aws" {
|
||||
return fmt.Errorf("user exec plugun command is invalid")
|
||||
if hubUser.Exec.Command != "/awscli/dist/aws" {
|
||||
return fmt.Errorf("user exec plugin command is invalid")
|
||||
}
|
||||
|
||||
hubClusterAccountId, hubClusterName := helpers.GetAwsAccountIdAndClusterName(hubClusterArn)
|
||||
@@ -168,7 +168,7 @@ var _ = ginkgo.Describe("Joining Process for aws flow", func() {
|
||||
|
||||
// run registration agent
|
||||
agentOptions := &spoke.SpokeAgentOptions{
|
||||
RegistrationAuth: spoke.AwsIrsaAuthType,
|
||||
RegistrationAuth: helpers.AwsIrsaAuthType,
|
||||
HubClusterArn: hubClusterArn,
|
||||
ManagedClusterArn: managedClusterArn,
|
||||
ManagedClusterRoleSuffix: managedClusterRoleSuffix,
|
||||
@@ -201,7 +201,7 @@ var _ = ginkgo.Describe("Joining Process for aws flow", func() {
|
||||
|
||||
// run registration agent
|
||||
agentOptions := &spoke.SpokeAgentOptions{
|
||||
RegistrationAuth: spoke.AwsIrsaAuthType,
|
||||
RegistrationAuth: helpers.AwsIrsaAuthType,
|
||||
HubClusterArn: hubClusterArn,
|
||||
ManagedClusterArn: managedClusterArn,
|
||||
ManagedClusterRoleSuffix: managedClusterRoleSuffix,
|
||||
|
||||
Reference in New Issue
Block a user