func (r *ReconcileAWSFederatedAccountAccess) createIAMPolicy(awsClient awsclient.Client, afr awsv1alpha1.AWSFederatedRole, afaa awsv1alpha1.AWSFederatedAccountAccess) (*iam.Policy, error) {
	type awsStatement struct {
		Effect    string                 `json:"Effect"`
		Action    []string               `json:"Action"`
		Resource  []string               `json:"Resource,omitempty"`
		Condition *awsv1alpha1.Condition `json:"Condition,omitempty"`
		Principal *awsv1alpha1.Principal `json:"Principal,omitempty"`
	}
	statements := []awsStatement{}
	for _, sm := range afr.Spec.AWSCustomPolicy.Statements {
		var a awsStatement = awsStatement(sm)
		statements = append(statements, a)
	}
	policyDoc := struct {
		Version   string
		Statement []awsStatement
	}{
		Version:   "2012-10-17",
		Statement: statements,
	}
	jsonPolicyDoc, err := json.Marshal(&policyDoc)
	if err != nil {
		return &iam.Policy{}, fmt.Errorf("Error marshalling jsonPolicy doc : Error %s", err.Error())
	}
	var policyName string
	if uidLabel, ok := afaa.Labels["uid"]; ok {
		policyName = afr.Spec.AWSCustomPolicy.Name + "-" + uidLabel
	} else {
		return nil, errors.New("Failed to get UID label")
	}
	output, err := awsClient.CreatePolicy(&iam.CreatePolicyInput{
		PolicyName:     aws.String(policyName),
		Description:    aws.String(afr.Spec.AWSCustomPolicy.Description),
		PolicyDocument: aws.String(string(jsonPolicyDoc)),
	})
	if err != nil {
		return nil, err
	}
	return output.Policy, nil
}
createIAMPolicy creates the IAM policys in AWSFederatedRole inside of our cluster account
package awsfederatedaccountaccess
import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/iam"
	"github.com/aws/aws-sdk-go/service/sts"
	"github.com/go-logr/logr"
	"k8s.io/apimachinery/pkg/types"
	awsv1alpha1 "github.com/openshift/aws-account-operator/pkg/apis/aws/v1alpha1"
	"github.com/openshift/aws-account-operator/pkg/awsclient"
	controllerutils "github.com/openshift/aws-account-operator/pkg/controller/utils"
	corev1 "k8s.io/api/core/v1"
	k8serr "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/runtime"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/controller"
	"sigs.k8s.io/controller-runtime/pkg/handler"
	logf "sigs.k8s.io/controller-runtime/pkg/log"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/reconcile"
	"sigs.k8s.io/controller-runtime/pkg/source"
)
const (
	controllerName = "awsfederatedaccountaccess"
)
var ErrFederatedAccessRoleNotFound = errors.New("FederatedAccessRoleNotFound")
var ErrFederatedAccessRoleFailedCreate = errors.New("FederatedAccessRoleFailedCreate")
var log = logf.Log.WithName("controller_awsfederatedaccountaccess")
func Add(mgr manager.Manager) error {
	return add(mgr, newReconciler(mgr))
}
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
	reconciler := &ReconcileAWSFederatedAccountAccess{
		client:           controllerutils.NewClientWithMetricsOrDie(log, mgr, controllerName),
		scheme:           mgr.GetScheme(),
		awsClientBuilder: &awsclient.Builder{},
	}
	return controllerutils.NewReconcilerWithMetrics(reconciler, controllerName)
}
func add(mgr manager.Manager, r reconcile.Reconciler) error {
	c, err := controller.New("awsfederatedaccountaccess-controller", mgr, controller.Options{Reconciler: r})
	if err != nil {
		return err
	}
	err = c.Watch(&source.Kind{Type: &awsv1alpha1.AWSFederatedAccountAccess{}}, &handler.EnqueueRequestForObject{})
	if err != nil {
		return err
	}
	return nil
}
var _ reconcile.Reconciler = &ReconcileAWSFederatedAccountAccess{}
type ReconcileAWSFederatedAccountAccess struct {
	client           client.Client
	scheme           *runtime.Scheme
	awsClientBuilder awsclient.IBuilder
}
func (r *ReconcileAWSFederatedAccountAccess) Reconcile(request reconcile.Request) (reconcile.Result, error) {
	reqLogger := log.WithValues("Controller", controllerName, "Request.Namespace", request.Namespace, "Request.Name", request.Name)
	currentFAA := &awsv1alpha1.AWSFederatedAccountAccess{}
	err := r.client.Get(context.TODO(), request.NamespacedName, currentFAA)
	if err != nil {
		if k8serr.IsNotFound(err) {
			return reconcile.Result{}, nil
		}
		return reconcile.Result{}, err
	}
	requestedRole := &awsv1alpha1.AWSFederatedRole{}
	err = r.client.Get(context.TODO(), types.NamespacedName{Name: currentFAA.Spec.AWSFederatedRole.Name, Namespace: currentFAA.Spec.AWSFederatedRole.Namespace}, requestedRole)
	if err != nil {
		if k8serr.IsNotFound(err) {
			SetStatuswithCondition(currentFAA, "Requested role does not exist", awsv1alpha1.AWSFederatedAccountFailed, awsv1alpha1.AWSFederatedAccountStateFailed)
			reqLogger.Error(ErrFederatedAccessRoleNotFound, fmt.Sprintf("Requested role %s not found", currentFAA.Spec.AWSFederatedRole.Name))
			err := r.client.Status().Update(context.TODO(), currentFAA)
			if err != nil {
				reqLogger.Error(err, fmt.Sprintf("Status update for %s failed", currentFAA.Name))
				return reconcile.Result{}, err
			}
			return reconcile.Result{}, nil
		}
		return reconcile.Result{}, err
	}
	if !controllerutils.Contains(currentFAA.GetFinalizers(), controllerutils.Finalizer) {
		err := r.addFinalizer(reqLogger, currentFAA)
		if err != nil {
			return reconcile.Result{}, err
		}
		return reconcile.Result{}, nil
	}
	if currentFAA.DeletionTimestamp != nil {
		if controllerutils.Contains(currentFAA.GetFinalizers(), controllerutils.Finalizer) {
			reqLogger.Info("Cleaning up FederatedAccountAccess Roles")
			err = r.cleanFederatedRoles(reqLogger, currentFAA, requestedRole)
			if err != nil {
				return reconcile.Result{}, err
			}
			reqLogger.Info("Removing Finalizer")
			err = r.removeFinalizer(reqLogger, currentFAA, controllerutils.Finalizer)
			if err != nil {
				return reconcile.Result{}, err
			}
		}
	}
	if currentFAA.Status.State == awsv1alpha1.AWSFederatedAccountStateReady || currentFAA.Status.State == awsv1alpha1.AWSFederatedAccountStateFailed {
		return reconcile.Result{}, nil
	}
	if !hasLabel(currentFAA, awsv1alpha1.UIDLabel) {
		uid := controllerutils.GenerateShortUID()
		reqLogger.Info(fmt.Sprintf("Adding UID %s to AccountAccess %s", uid, currentFAA.Name))
		newLabel := map[string]string{"uid": uid}
		if currentFAA.Labels != nil {
			currentFAA.Labels = controllerutils.JoinLabelMaps(currentFAA.Labels, newLabel)
		} else {
			currentFAA.Labels = newLabel
		}
		err = r.client.Update(context.TODO(), currentFAA)
		if err != nil {
			reqLogger.Error(err, fmt.Sprintf("Lable update for %s failed", currentFAA.Name))
			return reconcile.Result{}, err
		}
	}
	uidLabel, ok := currentFAA.Labels[awsv1alpha1.UIDLabel]
	if !ok {
		return reconcile.Result{}, err
	}
	awsClient, err := r.awsClientBuilder.GetClient(controllerName, r.client, awsclient.NewAwsClientInput{
		SecretName: currentFAA.Spec.AWSCustomerCredentialSecret.Name,
		NameSpace:  currentFAA.Spec.AWSCustomerCredentialSecret.Namespace,
		AwsRegion:  "us-east-1",
	})
	if err != nil {
		reqLogger.Error(err, "Unable to create aws client for region ")
		return reconcile.Result{}, err
	}
	gciOut, err := awsClient.GetCallerIdentity(&sts.GetCallerIdentityInput{})
	if err != nil {
		SetStatuswithCondition(currentFAA, "Failed to get account ID information", awsv1alpha1.AWSFederatedAccountFailed, awsv1alpha1.AWSFederatedAccountStateFailed)
		controllerutils.LogAwsError(log, fmt.Sprintf("Failed to get account ID information for '%s'", currentFAA.Name), err, err)
		err := r.client.Status().Update(context.TODO(), currentFAA)
		if err != nil {
			reqLogger.Error(err, fmt.Sprintf("Status update for %s failed", currentFAA.Name))
			return reconcile.Result{}, err
		}
		return reconcile.Result{}, err
	}
	accountID := *gciOut.Account  
	if !hasLabel(currentFAA, awsv1alpha1.AccountIDLabel) {
		reqLogger.Info(fmt.Sprintf("Adding awsAccountID %s to AccountAccess %s", accountID, currentFAA.Name))
		newLabel := map[string]string{"awsAccountID": accountID}
		if currentFAA.Labels != nil {
			currentFAA.Labels = controllerutils.JoinLabelMaps(currentFAA.Labels, newLabel)
		} else {
			currentFAA.Labels = newLabel
		}
		err = r.client.Update(context.TODO(), currentFAA)
		if err != nil {
			reqLogger.Error(err, fmt.Sprintf("Label update for %s failed", currentFAA.Name))
			return reconcile.Result{}, err
		}
	}
	err = r.createOrUpdateIAMPolicy(awsClient, *requestedRole, *currentFAA)
	if err != nil {
		SetStatuswithCondition(currentFAA, "Failed to create custom policy", awsv1alpha1.AWSFederatedAccountFailed, awsv1alpha1.AWSFederatedAccountStateFailed)
		reqLogger.Error(err, fmt.Sprintf("Unable to create policy requested by '%s'", currentFAA.Name))
		err := r.client.Status().Update(context.TODO(), currentFAA)
		if err != nil {
			reqLogger.Error(err, fmt.Sprintf("Status update for %s failed", currentFAA.Name))
			return reconcile.Result{}, err
		}
		return reconcile.Result{}, nil
	}
	role, err := r.createOrUpdateIAMRole(awsClient, *requestedRole, *currentFAA, reqLogger)
	if err != nil {
		SetStatuswithCondition(currentFAA, "Failed to create role", awsv1alpha1.AWSFederatedAccountFailed, awsv1alpha1.AWSFederatedAccountStateFailed)
		reqLogger.Error(ErrFederatedAccessRoleFailedCreate, fmt.Sprintf("Unable to create role requested by '%s'", currentFAA.Name), "AWS ERROR: ", err)
		err := r.client.Status().Update(context.TODO(), currentFAA)
		if err != nil {
			reqLogger.Error(err, fmt.Sprintf("Status update for %s failed", currentFAA.Name))
			return reconcile.Result{}, err
		}
		return reconcile.Result{}, nil
	}
	currentFAA.Status.ConsoleURL = fmt.Sprintf("https://signin.aws.amazon.com/switchrole?account=%s&roleName=%s", accountID, *role.RoleName)
	awsManagedPolicyNames := []string{}
	awsManagedPolicyNames = append(awsManagedPolicyNames, requestedRole.Spec.AWSManagedPolicies...)
	policyArns := createPolicyArns(accountID, awsManagedPolicyNames, true)
	customPolicy := []string{requestedRole.Spec.AWSCustomPolicy.Name + "-" + uidLabel}
	customerPolArns := createPolicyArns(accountID, customPolicy, false)
	policyArns = append(policyArns, customerPolArns[0])
	err = r.attachIAMPolices(awsClient, currentFAA.Spec.AWSFederatedRole.Name+"-"+uidLabel, policyArns)
	if err != nil {
		SetStatuswithCondition(currentFAA, "Failed to attach policies to role", awsv1alpha1.AWSFederatedAccountFailed, awsv1alpha1.AWSFederatedAccountStateFailed)
		reqLogger.Error(err, fmt.Sprintf("Failed to attach policies to role requested by '%s'", currentFAA.Name))
		err := r.client.Status().Update(context.TODO(), currentFAA)
		if err != nil {
			reqLogger.Error(err, fmt.Sprintf("Status update for %s failed", currentFAA.Name))
			return reconcile.Result{}, err
		}
		return reconcile.Result{}, nil
	}
	SetStatuswithCondition(currentFAA, "Account Access Ready", awsv1alpha1.AWSFederatedAccountReady, awsv1alpha1.AWSFederatedAccountStateReady)
	reqLogger.Info(fmt.Sprintf("Successfully applied %s", currentFAA.Name))
	err = r.client.Status().Update(context.TODO(), currentFAA)
	if err != nil {
		reqLogger.Error(err, fmt.Sprintf("Status update for %s failed", currentFAA.Name))
		return reconcile.Result{}, err
	}
	return reconcile.Result{}, nil
}