Create Tenant project
Duration: 10 min | Persona: Org Admin
In this section, you will create the Tenant project. The Tenant project will contain all the Google Cloud resources needed in this workshop.
Define variables:
WORK_DIR=~/
source ${WORK_DIR}acm-workshop-variables.sh
TENANT_PROJECT_ID=acm-workshop-${RANDOM_SUFFIX}-tenant
echo "export TENANT_PROJECT_ID=${TENANT_PROJECT_ID}" >> ${WORK_DIR}acm-workshop-variables.sh
echo "export TENANT_PROJECT_SA_EMAIL=${TENANT_PROJECT_ID}@${HOST_PROJECT_ID}.iam.gserviceaccount.com" >> ${WORK_DIR}acm-workshop-variables.sh
source ${WORK_DIR}acm-workshop-variables.shCreate a dedicated folder for this Tenant project resources:
mkdir ${WORK_DIR}$HOST_PROJECT_DIR_NAME/projects
mkdir ${WORK_DIR}$HOST_PROJECT_DIR_NAME/projects/$TENANT_PROJECT_IDDefine GCP project
Define the GCP project either at the Folder level or the Organization level:
At the Folder level:
cat <<EOF > ${WORK_DIR}$HOST_PROJECT_DIR_NAME/projects/$TENANT_PROJECT_ID/project.yaml
apiVersion: resourcemanager.cnrm.cloud.google.com/v1beta1
kind: Project
metadata:
annotations:
cnrm.cloud.google.com/auto-create-network: "false"
name: ${TENANT_PROJECT_ID}
namespace: config-control
spec:
name: ${TENANT_PROJECT_ID}
billingAccountRef:
external: "${BILLING_ACCOUNT_ID}"
folderRef:
external: "${FOLDER_OR_ORG_ID}"
resourceID: ${TENANT_PROJECT_ID}
EOFAt the Organization level:
cat <<EOF > ${WORK_DIR}$HOST_PROJECT_DIR_NAME/projects/$TENANT_PROJECT_ID/project.yaml
apiVersion: resourcemanager.cnrm.cloud.google.com/v1beta1
kind: Project
metadata:
annotations:
cnrm.cloud.google.com/auto-create-network: "false"
name: ${TENANT_PROJECT_ID}
namespace: config-control
spec:
name: ${TENANT_PROJECT_ID}
billingAccountRef:
external: "${BILLING_ACCOUNT_ID}"
organizationRef:
external: "${FOLDER_OR_ORG_ID}"
resourceID: ${TENANT_PROJECT_ID}
EOFDefine Tenant project service account
cat <<EOF > ${WORK_DIR}$HOST_PROJECT_DIR_NAME/projects/$TENANT_PROJECT_ID/service-account.yaml
apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMServiceAccount
metadata:
name: ${TENANT_PROJECT_ID}
namespace: config-control
annotations:
config.kubernetes.io/depends-on: resourcemanager.cnrm.cloud.google.com/namespaces/config-control/Project/${TENANT_PROJECT_ID}
spec:
displayName: ${TENANT_PROJECT_ID}
EOFcat <<EOF > ${WORK_DIR}$HOST_PROJECT_DIR_NAME/projects/$TENANT_PROJECT_ID/workload-identity-user.yaml
apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMPartialPolicy
metadata:
name: ${TENANT_PROJECT_ID}-sa-wi-user
namespace: config-control
annotations:
config.kubernetes.io/depends-on: iam.cnrm.cloud.google.com/namespaces/config-control/IAMServiceAccount/${TENANT_PROJECT_ID}
spec:
resourceRef:
name: ${TENANT_PROJECT_ID}
kind: IAMServiceAccount
bindings:
- role: roles/iam.workloadIdentityUser
members:
- member: serviceAccount:${HOST_PROJECT_ID}.svc.id.goog[cnrm-system/cnrm-controller-manager-${TENANT_PROJECT_ID}]
EOFYou could see that we use the annotation config.kubernetes.io/depends-on, since the version 1.11 of Config Management we could declare resource dependencies between resource objects. KCC already handles dependencies with a retry loop with backoff, which can make things with long reconcile time even longer and generate warnings or errors on these resources. With that annotation we are optimizing these behaviors. We will use this annotation as much as we can throughout this workshop.
Define Tenant project namespace and ConfigConnectorContext
cat <<EOF > ${WORK_DIR}$HOST_PROJECT_DIR_NAME/projects/$TENANT_PROJECT_ID/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: ${TENANT_PROJECT_ID}
EOFcat <<EOF > ${WORK_DIR}$HOST_PROJECT_DIR_NAME/projects/$TENANT_PROJECT_ID/config-connector-context.yaml
apiVersion: core.cnrm.cloud.google.com/v1beta1
kind: ConfigConnectorContext
metadata:
name: configconnectorcontext.core.cnrm.cloud.google.com
namespace: ${TENANT_PROJECT_ID}
annotations:
config.kubernetes.io/depends-on: iam.cnrm.cloud.google.com/namespaces/config-control/IAMServiceAccount/${TENANT_PROJECT_ID}
spec:
billingProject: ${TENANT_PROJECT_ID}
googleServiceAccount: ${TENANT_PROJECT_SA_EMAIL}
requestProjectPolicy: BILLING_PROJECT
EOFDeploy Kubernetes manifests
cd ${WORK_DIR}$HOST_PROJECT_DIR_NAME/
git add . && git commit -m "Setting up Tenant namespace/project" && git push origin mainCheck deployments
graph TD; IAMServiceAccount-->Project IAMPartialPolicy-->IAMServiceAccount ConfigConnectorContext-->IAMServiceAccount
List the Kubernetes resources managed by Config Sync in Config Controller for the Host project configs repository:
Run this command and click on this link:
echo -e "https://console.cloud.google.com/kubernetes/config_management/packages?project=${HOST_PROJECT_ID}"Wait until you see the Sync status column as Synced and the Reconcile status column as Current.
Run this command:
gcloud alpha anthos config sync repo describe \
--project $HOST_PROJECT_ID \
--managed-resources all \
--sync-name root-sync \
--sync-namespace config-management-systemWait and re-run this command above until you see "status": "SYNCED". All the managed_resources listed should have STATUS: Current too.
List the GitHub runs for the Host project configs repository:
cd ${WORK_DIR}$HOST_PROJECT_DIR_NAME && gh run listList the Google Cloud resources created:
gcloud projects describe $TENANT_PROJECT_ID
gcloud iam service-accounts describe $TENANT_PROJECT_SA_EMAIL \
--project $HOST_PROJECT_IDResolve Tenant project creation issue
Let’s make sure that the Tenant project has been successfully created.
Run this command below:
kubectl get gcpproject -n config-controlIf the output is similar to this below (STATUS UpToDate), you are good and you could move forward to the next page:
NAME AGE READY STATUS STATUS AGE
acm-workshop-742-tenant 50m True UpToDate 47mBut if you have this output below (STATUS UpdateFailed), that’s where you will need to take actions:
NAME AGE READY STATUS STATUS AGE
acm-workshop-742-tenant 50m True UpdateFailed 47mRun this command below to have a closer look at the details of the error:
kubectl describe gcpproject -n config-controlThe error you may have could be similar to:
Update call failed: error applying desired state: summary: failed pre-requisites: missing permission on "billingAccounts/XXX": billing.resourceAssociations.createWe will resolve this issue by redeploying the Project resource by removing the billingAccountRef part.
Update the GCP project either at the Folder level or the Organization level:
At the Folder level:
cat <<EOF > ${WORK_DIR}$HOST_PROJECT_DIR_NAME/projects/$TENANT_PROJECT_ID/project.yaml
apiVersion: resourcemanager.cnrm.cloud.google.com/v1beta1
kind: Project
metadata:
annotations:
cnrm.cloud.google.com/auto-create-network: "false"
name: ${TENANT_PROJECT_ID}
namespace: config-control
spec:
name: ${TENANT_PROJECT_ID}
folderRef:
external: "${FOLDER_OR_ORG_ID}"
resourceID: ${TENANT_PROJECT_ID}
EOFAt the Organization level:
cat <<EOF > ${WORK_DIR}$HOST_PROJECT_DIR_NAME/projects/$TENANT_PROJECT_ID/project.yaml
apiVersion: resourcemanager.cnrm.cloud.google.com/v1beta1
kind: Project
metadata:
annotations:
cnrm.cloud.google.com/auto-create-network: "false"
name: ${TENANT_PROJECT_ID}
namespace: config-control
spec:
name: ${TENANT_PROJECT_ID}
organizationRef:
external: "${FOLDER_OR_ORG_ID}"
resourceID: ${TENANT_PROJECT_ID}
EOFRe-deploy the Project resource:
cd ${WORK_DIR}$HOST_PROJECT_DIR_NAME/
git add . && git commit -m "Remove the billingAccountRef in order to create Tenant Project" && git push origin mainWait for status SYNCED with this command:
gcloud alpha anthos config sync repo describe \
--project $HOST_PROJECT_ID \
--managed-resources all \
--sync-name root-sync \
--sync-namespace config-management-systemAnd then, check that the Google Cloud project is created:
gcloud projects describe $TENANT_PROJECT_IDThen what you have to do is to manually assign the Billing Account to this project by running by yourself this command below:
gcloud beta billing projects link $TENANT_PROJECT_ID \
--billing-account $BILLING_ACCOUNT_IDIf you can’t run the command above, the alternative is having someone in your organization (Billing Account or Organization admins) running it for you.