Entitle agent installation

Overview

This guide will walk you through the steps required to set up Entitle's agent in your chosen Kubernetes cluster, kubernetes is a must for this procedure.

Prerequisites

Before setting up Entitle's agent, please make sure the following are configured within your Kubernetes cluster:

  1. Make sure Datadog and Entitle's Helm charts are installed in your cluster by running the following commands:
helm repo add datadog https://helm.datadoghq.com
helm repo add entitle https://anycred.github.io/entitle-charts/
  1. Generate a new agent token in Entitle's Org Settings page, and save it for further usage.

Kubernetes Secret Manager Installation (Default)

Kubernetes Secret Manager Installation (default)

📘

Note

The Kubernetes Secret Manager installation type is set to be the default secret manager even if your K8s cluster is hosted on GCP/AWS/Azure

Chart installation

  • IMAGE_CREDENTIALS and DATADOG_API_KEY - for further details, see Entitle Security FAQ article in the BeyondTrust Knowledge Base.
  • The agent.token value was created as a part of the Prerequisites section above.
  • The <ORG_NAME> value within the datadog.tags key should be replaced with your company's name.
  • Although you can replace the entitle namespace with your namespace, it is highly discouraged.
helm upgrade --install entitle-agent entitle/entitle-agent  ֿ\
    --set kmsType="kubernetes_secret_manager" \
    --set imageCredentials="${IMAGE_CREDENTIALS}"  \
    --set datadog.datadog.apiKey="${DATADOG_API_KEY}"  \
    --set datadog.datadog.tags={company:${ORG_NAME}}  \
    --set agent.token="${TOKEN}"  \
    -n ${NAMESPACE} --create-namespace

🎉 You're set to go! 🎉

GCP Installation

GCP installation

Workload Identity

Note: If you installed Entitle's IaC, you may skip to the chart installation part.

Update kubeconfig

  • If you have installed Entitle's Terraform IaC:

    You can set the environment variables using Terraform output file terraform_output.json:

    BASTION_HOSTNAME=$(jq -r '.bastion_hostname.value' terraform_output.json)
    PROJECT_ID=$(jq -r '.project_id.value' terraform_output.json)
    ZONE=$(jq -r '.zone.value' terraform_output.json)
    REGION=$(jq -r '.region.value' terraform_output.json)
    CLUSTER_NAME=$(jq -r '.cluster_name.value' terraform_output.json)
    ENTITLE_AGENT_GKE_SERVICE_ACCOUNT_NAME=$(jq -r '.entitle_agent_gke_service_account_name.value' terraform_output.json)
    TOKEN=$(jq -r '.token.value' terraform_output.json)
    COSTUMER_NAME=$(jq -r '.costumer_name.value' terraform_output.json)
    NAMESPACE=$(jq -r '.namespace.value' terraform_output.json)
    IMAGE_CREDENTIALS=$(jq -r '.image_credentials.value' terraform_output.json)
    DATADOG_API_KEY=$(jq -r '.datadog_api_key.value' terraform_output.json)
    BASTION_SETUP_COMMAND=$(jq -r '.bastion_setup_command.value' terraform_output.json)
    AUTOPILOT=$(jq -r '.autopilot.value' terraform_output.json)
    AGENT_MODE=$(jq -r '.agent_mode.value' terraform_output.json)
    

Setting up IAP-Tunnel

  • Run the following command, note that If AutoPilot is enabled, replace --zone with --region.
gcloud beta compute ssh "<BASTION_HOSTNAME>" --tunnel-through-iap --project "<PROJECT_ID>" --zone "<ZONE>" -- -4 -N -L 8888:127.0.0.1:8888 -o "ExitOnForwardFailure yes" -o "ServerAliveInterval 10" &
  • If your cluster isn't configured on kubeconfig yet:
    gcloud container clusters get-credentials "<CLUSTER_NAME>" --zone "<ZONE>" --project "<PROJECT_ID>" --internal-ip
    
  • Otherwise, simply replace <CLUSTER_NAME> and <ZONE> and run the following command:
    gcloud container clusters get-credentials <CLUSTER_NAME> --zone <ZONE>
    

export HTTPS_PROXY=localhost:8888
  • If you wish to use Hashicorp vault, set kmsType to hashicorp_vault:
helm upgrade --install entitle-agent entitle/entitle-agent \
  --set platform.mode="gcp" \
  --set kmsType="gcp_secret_manager" \
  --set imageCredentials="<IMAGE_CREDENTIALS>" \
  --set datadog.datadog.apiKey="<DATADOG_API_KEY>" \
  --set platform.gke.serviceAccount="<ENTITLE_AGENT_GKE_SERVICE_ACCOUNT_NAME>" \
  --set platform.gke.projectId="<PROJECT_ID>" \
  --set agent.token="<AGENT_TOKEN_FROM_ENTITLES_ORG_SETTINGS>" \
  --set datadog.datadog.tags={company:<YOUR_ORG_NAME>} \
  -n "<NAMESPACE>" --create-namespace
  • If you set up environment variables, please use the following command:
helm upgrade --install entitle-agent entitle/entitle-agent \
  --set platform.mode="gcp" \
  --set kmsType="gcp_secret_manager" \
  --set imageCredentials="${IMAGE_CREDENTIALS}" \
  --set datadog.datadog.apiKey="${DATADOG_API_KEY}" \
  --set datadog.providers.gke.autopilot="${AUTOPILOT}" \
  --set platform.gke.serviceAccount="${ENTITLE_AGENT_GKE_SERVICE_ACCOUNT_NAME}" \
  --set platform.gke.projectId="${PROJECT_ID}" \
  --set agent.token="${TOKEN}" \
  --set datadog.datadog.tags={company:${ORGANIZATION_NAME}} \
  -n "${NAMESPACE}" --create-namespace
AWS Installation

AWS installation

Declare variables

  • Define bash variable for CLUSTER_NAME:
    CLUSTER_NAME=<your-cluster-name>
  • Define your cluster's name:
 export CLUSTER_NAME=<your-cluster-name>
  • Update kubeconfig:
    aws eks update-kubeconfig --name $CLUSTER_NAME --region us-east-2 # Or any other region
 aws eks update-kubeconfig --name $CLUSTER_NAME --region us-east-2   # (or any other region)

⚠️Note: If you installed our IaC then you may now skip to the chart installation part

You can check if you already have the Identity Provider for your cluster using one of the following:

  • Run the following command:
    aws eks describe-cluster --name $CLUSTER_NAME --query "cluster.identity.oidc.issuer" --output text
  • Or here.
  • Run the following command:
      aws eks describe-cluster --name $CLUSTER_NAME --query "cluster.identity.oidc.issuer" --output text
    
  • Alternatively, refer to IAM Identity Providers page in the AWS Console.

If you don't have an OIDC provider, please create a new one by running the following command:

eksctl utils associate-iam-oidc-provider --cluster $CLUSTER_NAME --approve

Create policy

ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
echo $ACCOUNT_ID

cat > entitle-agent-policy.json <<ENDOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
              "secretsmanager:UpdateSecret",
              "secretsmanager:TagResource",
              "secretsmanager:PutSecretValue",
              "secretsmanager:ListSecretVersionIds",
              "secretsmanager:GetSecretValue",
              "secretsmanager:GetResourcePolicy",
              "secretsmanager:DescribeSecret",
              "secretsmanager:DeleteSecret",
              "secretsmanager:CreateSecret"
            ],
            "Resource": "arn:aws:secretsmanager:*:${ACCOUNT_ID}:secret:Entitle/*"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "secretsmanager:ListSecrets",
            "Resource" : "*"
        }
    ]
}
ENDOF

aws iam create-policy --policy-name entitle-agent-policy --policy-document file://entitle-agent-policy.json

Create IAM role and attach policy

ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
echo $ACCOUNT_ID
OIDC_PROVIDER=$(aws eks describe-cluster --name ${CLUSTER_NAME} --query "cluster.identity.oidc.issuer" --output text | sed -e "s/^https:\/\///")
echo $OIDC_PROVIDER

cat > trust.json <<ENDOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::${ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "${OIDC_PROVIDER}:aud": "sts.amazonaws.com",
          "${OIDC_PROVIDER}:sub": "system:serviceaccount:entitle:entitle-agent-sa"
        }
      }
    }
  ]
}
ENDOF

aws iam create-role --role-name entitle-agent-role --assume-role-policy-document file://trust.json --description "Entitle Agent's AWS Role"
aws iam attach-role-policy --role-name entitle-agent-role --policy-arn=arn:aws:iam::${ACCOUNT_ID}:policy/entitle-agent-policy

Eventually, you can install our Helm chart:

  • IMAGE_CREDENTIAL and DATADOG_API_KEY - for further details, see Entitle Security FAQ article in the BeyondTrust Knowledge Base.
  • The agent.token value was created as a part of the Prerequisites section above.
  • The <ORG_NAME> value within the datadog.tags key should be replaced with your company's name.
  • Replace platform.aws.iamRole with Entitle's AWS IAM Role, you've created.
  • Although you can replace the entitle namespace with your namespace, it is highly discouraged.
  • If you want to use Hashicorp vault, set kmsType to hashicorp_vault.
export IMAGE_CREDENTIALS=<IMAGE_CREDENTIALS>
export DATADOG_API_KEY=<DATADOG_API_KEY>
export TOKEN=<TOKEN_FROM_ENTITLES_ORG_SETTINGS>
export ORG_NAME=<YOUR ORGANIZATION NAME>
export NAMESPACE=entitle

helm upgrade --install entitle-agent entitle/entitle-agent \
    --set platform.mode="aws" \
    --set kmsType="aws_secret_manager" \
    --set imageCredentials=${IMAGE_CREDENTIALS} \
    --set datadog.datadog.apiKey=${DATADOG_API_KEY} \
    --set datadog.datadog.tags={company:${ORG_NAME}} \
    --set platform.aws.iamRole="arn:aws:iam::${ACCOUNT_ID}:role/entitle-agent-role" \
    --set agent.token="${TOKEN}" \
    -n ${NAMESPACE} --create-namespace

🎉 You're set to go! 🎉

Azure Installation

Azure installation

By the end of the installation, you will have a fully working Entitle agent on your Azure Kubernetes cluster.
The installation will be based on the following reading materials:

Reading Material

Prerequisites

Setup Environment Variables

export CLUSTER_NAME=<YOUR_AKS_CLUSTER_NAME>
export RESOURCE_GROUP=<YOUR_AKS_RESOURCE_GROUP>
export SUBSCRIPTION_ID=<YOUR_AZURE_SUBSCRIPTION_ID>
export LOCATION=<YOUR_AKS_LOCATION>
export NAMESPACE="entitle"
export SERVICE_ACCOUNT_NAME="entitle-agent-sa"
export WORKLOAD_IDENTITY_NAME=<YOUR_WORKLOAD_IDENTITY_NAME>
export FEDERATED_IDENTITY_NAME=<YOUR_FEDERATED_IDENTITY_NAME>
export KEY_VAULT_NAME=<YOUR_KEY_VAULT_NAME>
export AAD_GROUP_OBJECT_ID=<YOUR_AAD_GROUP_OBJECT_ID>
  • The variables CLUSTER_NAME, RESOURCE_GROUP, SUBSCRIPTION_ID, LOCATION can be found on the AKS cluster overview page.
    The other variables are up to you. (we highly recommend not changing the NAMESPACE and SERVICE_ACCOUNT_NAME)
  • If you don't have a managed identity created and assigned to your pod, perform the following steps to create and grant the necessary permissions to Key Vault.
  • Set account subscription.
az account set --subscription ${SUBSCRIPTION_ID}
  • Install the aks-preview extension.
az extension add --name aks-preview
az extension update --name aks-preview
  • Register EnablePodIdentityPreview feature.
az feature register --namespace Microsoft.ContainerService --name EnablePodIdentityPreview
  • It takes a few minutes for the status to show Registered. Verify the registration status by using the command:
 watch -g -n 5 az feature show --namespace "Microsoft.ContainerService" --name "EnableWorkloadIdentityPreview"

⚠️ The -g or --chgexit option causes the watch command to exit if there is a change in the output.

  • You'll get this message: Once the feature 'EnablePodIdentityPreview' is registered, invoking 'az provider register -n Microsoft.ContainerService' is required to get the change propagated.
  • Run the following command:
 az provider register --namespace Microsoft.ContainerService
  • Enable AAD/OIDC/WORKLOAD IDENTITY for the cluster.
  • Verify that all the below are not False/Null.
echo "$(az aks show -n ${CLUSTER_NAME} -g ${RESOURCE_GROUP} --query "oidcIssuerProfile.issuerUrl" -otsv)"
echo "$(az aks show -n ${CLUSTER_NAME} -g ${RESOURCE_GROUP} --query "securityProfile.workloadIdentity" -otsv)"
echo "$(az aks show -n ${CLUSTER_NAME} -g ${RESOURCE_GROUP} --query "aadProfile" -otsv)"
  • If any of the above is False/Null, run the following command (with the right flags) to enable AAD/OIDC/WORKLOAD IDENTITY for the cluster:
az aks update --resource-group ${RESOURCE_GROUP} --name ${CLUSTER_NAME} --enable-aad --aad-admin-group-object-ids ${AAD_GROUP_OBJECT_ID}  --enable-workload-identity --enable-oidc-issuer
  • Use the az identity create command to create a managed identity.
az identity create --name "${WORKLOAD_IDENTITY_NAME}" --resource-group "${RESOURCE_GROUP}" --location "${LOCATION}" --subscription "${SUBSCRIPTION_ID}"
export USER_ASSIGNED_CLIENT_ID="$(az identity show --resource-group "${RESOURCE_GROUP}" --name "${WORKLOAD_IDENTITY_NAME}" --query 'clientId' -otsv)"
export TENANT_ID=$(az aks show --name ${CLUSTER_NAME} --resource-group "${RESOURCE_GROUP}" --query aadProfile.tenantId -o tsv)
  • Grant the managed identity the permissions required to access the resources in Azure it requires.
az keyvault set-policy -n ${KEY_VAULT_NAME} --secret-permissions get set list delete --spn $USER_ASSIGNED_CLIENT_ID
  • To get the OIDC Issuer URL and save it to an environmental variable, run the following command:
export AKS_OIDC_ISSUER="$(az aks show -n ${CLUSTER_NAME} -g ${RESOURCE_GROUP} --query "oidcIssuerProfile.issuerUrl" -otsv)"
echo "AKS_OIDC_ISSUER: ${AKS_OIDC_ISSUER}"
  • Set credentials for kubectl to connect to your AKS cluster:
az aks get-credentials -n ${CLUSTER_NAME} -g "${RESOURCE_GROUP}" --admin

⚠️ --admin is optional, if you have a user with sufficient permissions you can omit it

  • Use the az identity federated-credential create command to create the federated identity credential between the managed identity, the service account issuer, and the subject.
az identity federated-credential create --name ${FEDERATED_IDENTITY_NAME} --identity-name ${WORKLOAD_IDENTITY_NAME} --resource-group ${RESOURCE_GROUP} --issuer ${AKS_OIDC_ISSUER} --subject system:serviceaccount:${NAMESPACE}:${SERVICE_ACCOUNT_NAME}
  • Login with kubelogin.
    There are several ways to log in with kubelogin according to the documentation, but we recommend using the interactive login:
export KUBECONFIG=<PATH_TO_KUBECONFIG>
kubelogin convert-kubeconfig
kubectl get no
  • You will get the following message:
    To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code ARJFDH6FU to authenticate.
    Follow the instructions and log in with your Azure account. After that, you should see the nodes of your cluster.

Chart installation

export IMAGE_CREDENTIALS=<IMAGE_CREDENTIALS>
export DATADOG_API_KEY=<DATADOG_API_KEY>
export TOKEN=<TOKEN_FROM_ENTITLES_ORG_SETTINGS>
export ORG_NAME=<YOUR ORGANIZATION NAME> 
  • If you wish to use Hashicorp vault, set kmsType to hashicorp_vault:

    helm upgrade --install entitle-agent entitle/entitle-agent \
    --set platform.mode="azure" \
    --set kmsType="azure_secret_manager" \
    --set imageCredentials=${IMAGE_CREDENTIALS} \
    --set datadog.datadog.apiKey=${DATADOG_API_KEY} \
    --set datadog.datadog.tags={company:${ORG_NAME}} \
    --set datadog.datadog.kubelet.tlsVerify=false \
    --set datadog.datadog.kubelet.host.valueFrom.fieldRef.fieldPath="spec.nodeName" \
    --set datadog.datadog.kubelet.hostCAPath="/etc/kubernetes/certs/kubeletserver.crt" \
    --set platform.azure.clientId=${USER_ASSIGNED_CLIENT_ID} \
    --set platform.azure.tenantId=${TENANT_ID} \
    --set platform.azure.keyVaultName=${KEY_VAULT_NAME} \
    --set agent.token="${TOKEN}" \
    -n ${NAMESPACE} --create-namespace
    

    🎉 You're set to go! 🎉

Configuration

The following table lists the configurable parameters of the Entitle agent chart and their default values.

ParameterDescriptionDefaultRequired input by user
imageCredentialsCredentials you've received upon agent installation (Contact us for more info)nulltrue
kmsTypeKMS for the agent to save secrets. Taken value from ["aws_secret_manager","gcp_secret_manager","azure_secret_manager","hashicorp_vault"]nulltrue
platform.modeTake values from: [AWS, GCP, Azure]"gcp"true
platform.aws.iamRoleIAM role for agent's service account annotationsnulltrue if platform.mode="aws"
platform.gke.serviceAccountGKE service account for agent's service account annotationsnulltrue if mode="platform.gcp"
platform.gke.projectIdGCP project ID for agent's service account annotationsnulltrue if mode="platform.gcp"
platform.azure.clientIdAzure AD application client ID to be used with the pod (USER_ASSIGNED_CLIENT_ID from above)nulltrue if mode="platform.azure"
platform.azure.tenantIdAzure AD tenant ID to be used with the pod.nulltrue if mode="platform.azure"
platform.azure.keyVaultNameName of the Azure Key Vault to be used for storing the agent secretsnulltrue if mode="platform.azure"
podAnnotationshttps://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/{}false
nodeSelectorhttps://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector{}false
global.environmentUsed for metadata of deployment"onprem"false
agent.image.repositoryDocker image repository"ghcr.io/anycred/entitle-agent"false
agent.image.tagTag for docker image of the agent"master"false
agent.replicasNumber of pods to run1false
agent.resources.requests.cpuCPU request for agent pod"500m"false
agent.resources.requests.memoryMemory request for agent pod"1Gi"false
agent.resources.limits.cpuCPU limit for agent pod"1000m"false
agent.resources.limits.memoryMemory limit for agent pod"3Gi"false
agent.tokenCredentials you've received upon agent installation (Contact us for more info)nulltrue
datadog.providers.gke.autopilotWhether to enable autopilot or notfalsefalse
datadog.datadog.apiKeyDatadog API keynulltrue
datadog.datadog.tagsDatadog Tag - add your company name (https://docs.datadoghq.com/tagging/)nulltrue