# Installing a connector on Kubernetes with AWS permissions

{% hint style="info" %}
You have chosen the advanced installation method

You can also easily connect AWS in Apono following this UI guide [here](https://github.com/apono-io/Gitbook-docs/blob/main/documentation-and-guides/kubernetes-environment/apono-connector-for-kubernetes/aws-cloud/README.md)
{% endhint %}

## How to install the Connector on Kubernetes

### Prerequisite

It's required that you have your Cloud Account connected to your Kubernetes Cluster\
In this example we use Kube2Iam solution for kubernetes on EC2

* [Kube2Iam](https://github.com/jtblin/kube2iam)

### Deploying the Connector

The Connector is deployed using helm and requires and IAM Role to be able to access tagged ASM secrets in the future.\
You can choose to install the Connector using either your CLI or Terraform:

**CLI**

* Create a IAM role to allow Connector read access for apono tagged secrets
* Get AWS Account
* Replace `#EKS_CLUSTER_NAME`

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

* Create Connector Role

```
aws iam create-role --role-name "{{K8S_SERVICE_ACCOUNT}}-{{CONNECTOR_ID}}" --assume-role-policy-document '{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {
      "Service": "ec2.amazonaws.com"
    },
    "Action": "sts:AssumeRole"
  }]
}'
```

* Assign Role Policies

```
aws iam put-role-policy --role-name "{{K8S_SERVICE_ACCOUNT}}-{{CONNECTOR_ID}}" --policy-name "apono-tagged-secrets-access-policy" --policy-document '{
  "Version": "2012-10-17",
  "Statement": [{
      "Effect": "Allow",
      "Action": [ "secretsmanager:GetSecretValue", "secretsmanager:DescribeSecret"],
      "Resource": "arn:aws:secretsmanager:*:'"${ACCOUNT_ID}"':secret:*",
      "Condition": { "StringEquals": {"aws:ResourceTag/apono-connector-read": "true"} }
    }]
}'

aws iam put-role-policy --role-name "{{K8S_SERVICE_ACCOUNT}}-{{CONNECTOR_ID}}" --policy-name "apono-tagged-kms-keys-access-policy" --policy-document '{  
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "kms:Sign",
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "aws:ResourceTag/apono-connector-read": "true"
                }
            }
        }
    ]
}'

aws iam put-role-policy --role-name "{{K8S_SERVICE_ACCOUNT}}-{{CONNECTOR_ID}}" --policy-name "apono-iam-policy" --policy-document '{
  "Version": "2012-10-17",
  "Statement": [{"Action":["iam:ListPolicies","iam:CreateInstanceProfile","iam:ListGroups","iam:ListInstanceProfiles"],
    "Effect":"Allow",
    "Resource":"*"},
    {"Action":["iam:CreateInstanceProfile","iam:GetRole","iam:UpdateAssumeRolePolicy","iam:ListRoleTags","iam:TagRole","iam:CreateRole","iam:DeleteRole","iam:AttachRolePolicy","iam:PutRolePolicy","iam:AddRoleToInstanceProfile","iam:ListInstanceProfilesForRole","iam:DetachRolePolicy","iam:ListAttachedRolePolicies","iam:DeleteRolePolicy","iam:ListAttachedGroupPolicies","iam:ListRolePolicies","iam:GetRolePolicy","iam:PassRole","iam:GetInstanceProfile","iam:CreateUser","iam:CreateAccessKey","iam:DeleteAccessKey","iam:PutUserPolicy","iam:DeleteUserPolicy","iam:GetUser","iam:GetUserPolicy","iam:ListAttachedUserPolicies","iam:ListUserPolicies","iam:UpdateLoginProfile","iam:ListAccessKeys","iam:AttachUserPolicy","iam:DetachUserPolicy","iam:CreateLoginProfile"],
    "Effect":"Allow",
    "Resource":["arn:aws:iam::*:instance-profile/*","arn:aws:iam::*:role/*","arn:aws:iam::*:group/*","arn:aws:iam::*:user/*"]}]
}'

aws iam put-role-policy --role-name "{{K8S_SERVICE_ACCOUNT}}-{{CONNECTOR_ID}}" --policy-name "apono-read-objects-policy" --policy-document '{
  "Version": "2012-10-17",
  "Statement": [{"Action":["rds:DescribeDBInstances","rds:ListTagsForResource"],
    "Effect":"Allow",
    "Resource":"arn:aws:rds:*:*:db:*"},
    {"Action":["ssm:GetParameters*"],
    "Effect":"Allow",
    "Resource":"arn:aws:ssm:*:*:parameter/*"},
    {"Action":["ssm:DescribeParameters"],
    "Effect":"Allow",
    "Resource":"*"},
    {"Action":["s3:GetBucketTagging","s3:ListAllMyBuckets","s3:ListBucket","s3:GetBucketLocation"],
    "Effect":"Allow",
    "Resource":"arn:aws:s3:::*"}]
}'

aws iam put-role-policy --role-name "{{K8S_SERVICE_ACCOUNT}}-{{CONNECTOR_ID}}" --policy-name "apono-read-resource-tags" --policy-document '{
  "Version": "2012-10-17",
  "Statement": [{
      "Effect": "Allow",
      "Action": "tag:GetResources",
      "Resource": "*"
    }]
}'
```

* Deploy Apono Connector

```
helm install apono-connector {{CONNECTOR_CHART_REPO}}/{{CONNECTOR_CHART_NAME}}/{{CONNECTOR_CHART_NAME}}-<<helmVersion>>.tgz \
    --namespace "{{K8S_NAMESPACE}}" \
    --set image.repository="{{CONNECTOR_IMAGE_REPO}}" \
    --set image.tag="<<connectorVersion>>" \
    --set gitSyncImage="{{GIT_SYNC_IMAGE}}" \
    --set githubAccessToken="{{GITHUB_ACCESS_TOKEN}}" \
    --set serviceAccount.name="{{K8S_SERVICE_ACCOUNT}}" \
    --set podAnnotations."iam\.amazonaws\.com/role"="{{K8S_SERVICE_ACCOUNT}}-{{CONNECTOR_ID}}" \
    --set apono.token="{{TOKEN}}" \
    --set apono.url="{{APONO_WEBSOCKET_URL}}" \
    --set apono.websocketSsl="{{APONO_WEBSOCKET_SSL}}" \
    --set apono.connectorId="{{CONNECTOR_ID}}" \
    --create-namespace
```

**Terraform**

* Required providers: `helm` (v2.5.1), `aws`, `kubernetes`

```
locals {
  apono_token = "{{TOKEN}}"
  apono_websocket_url = "{{APONO_WEBSOCKET_URL}}"
  apono_websocket_ssl = "{{APONO_WEBSOCKET_SSL}}"
  connector_id = "{{CONNECTOR_ID}}"
  connector_helm_repo = "{{CONNECTOR_CHART_REPO}}"
  connector_helm_chart = "{{CONNECTOR_CHART_NAME}}"
  connector_helm_chart_version = "<<helmVersion>>"
  connector_image_repo = "{{CONNECTOR_IMAGE_REPO}}"
  connector_image_tag = "<<connectorVersion>>"
  git_sync_image = "{{GIT_SYNC_IMAGE}}"
  github_access_token = "{{GITHUB_ACCESS_TOKEN}}"
  service_account_name = "{{K8S_SERVICE_ACCOUNT}}"
  namespace = "{{K8S_NAMESPACE}}"
}

data "aws_caller_identity" "aws_account" {
  
}

locals {
  aws_account_id = data.aws_caller_identity.aws_account.account_id
}


// agent deployment
resource "kubernetes_namespace_v1" "apono-namespace" {
  metadata {
    name = local.namespace
  }
}

resource "helm_release" "apono-connector" {
  name             = "apono-connector"
  repository       = local.connector_helm_repo
  chart            = local.connector_helm_chart
  version          = local.connector_helm_chart_version
  namespace        = kubernetes_namespace_v1.apono-namespace.metadata[0].name

  set {
    name = "image.repository"
    value = local.connector_image_repo
  }

  set {
    name = "image.tag"
    value = local.connector_image_tag
  }

  set {
    name  = "gitSyncImage"
    value = local.git_sync_image
  }

  set {
    name  = "githubAccessToken"
    value = local.github_access_token
  }

  set {
    name = "serviceAccount.name"
    value = local.service_account_name
  }
  
  set {
    name = "serviceAccount.awsRoleAccountId"
    value = local.aws_account_id
  }
  
  set {
    name = "podAnnotations."iam\.amazonaws\.com/role""
    value = "${local.service_account_name}-${local.connector_id}"
  }

  set {
    name  = "apono.token"
    value = local.apono_token
  }

  set {
    name  = "apono.url"
    value = local.apono_websocket_url
  }

  set {
    name  = "apono.websocketSsl"
    value = local.apono_websocket_ssl
  }

  set {
    name  = "apono.connectorId"
    value = local.connector_id
  }
}

// IAM role and access policy for apono tagged secrets
resource "aws_iam_role" "apono-connector" {
  name = "${local.service_account_name}-${local.connector_id}"

  assume_role_policy = jsonencode({
    "Version" : "2012-10-17",
    "Statement" : [
      {
        "Effect" : "Allow",
        "Principal": { "Service": "ec2.amazonaws.com"},
        "Action" : "sts:AssumeRole"
      }
    ]
  })
  
  inline_policy {
    name = "apono-tagged-keys-access-policy"

    policy = jsonencode({
      Version = "2012-10-17"
      Statement = [
        {
          Effect = "Allow"
          Action = [ "kms:Sign" ]
          Resource = "*"
          Condition = { "StringEquals": {"aws:ResourceTag/apono-connector-read": "true"} }
        },
      ]
    })
  }
  
  inline_policy {
    name = "apono-tagged-secrets-access-policy"

    policy = jsonencode({
      Version = "2012-10-17"
      Statement = [
        {
          Effect = "Allow"
          Action = [ "secretsmanager:GetSecretValue", "secretsmanager:DescribeSecret"]
          Resource = "arn:aws:secretsmanager:*:${local.aws_account_id}:secret:*"
          Condition = { "StringEquals": {"aws:ResourceTag/apono-connector-read": "true"} }
        },
      ]
    })
  }
  
  // for s3-iam-role resources
  inline_policy {
    name = "s3-list-policy"
    policy = jsonencode({
      Version = "2012-10-17"
      Statement = [
        {
          Effect = "Allow"
          Action = ["s3:GetBucketTagging", "s3:ListAllMyBuckets", "s3:ListBucket", "s3:GetBucketLocation"]
          Resource = "arn:aws:s3:::*"
        },
      ]
    })
  }
  
  // for mysql-rds resources
  inline_policy {
    name = "rds-list-policy"
    policy = jsonencode({
      Version = "2012-10-17"
      Statement = [
        {
          Effect = "Allow"
          Action = ["rds:DescribeDBInstances", "rds:ListTagsForResource"]
          Resource = "arn:aws:rds:*:*:db:*"
        },
      ]
    })
  }

  // for ssm-iam-role resources
  inline_policy {
    name = "ssm-params-list-policy"
    policy = jsonencode({
      Version = "2012-10-17"
      Statement = [
        {
          Effect = "Allow"
          Action = ["ssm:GetParameters*"]
          Resource = "arn:aws:ssm:*:*:parameter/*"
        },
        {
          Effect = "Allow"
          Action = ["ssm:DescribeParameters"]
          Resource = "*"
        },
      ]
    })
  }

  // for iam manipulation
  inline_policy {
    name = "iam-access-policy"
    policy = jsonencode({
      Version = "2012-10-17"
      Statement = [
        {
            Effect = "Allow"
            Action = [
                "iam:ListPolicies",
                "iam:CreateInstanceProfile",
                "iam:ListGroups",
                "iam:ListInstanceProfiles"
            ],
            Resource = "*"
        },
        {
            Effect = "Allow"
            Action = [
                "iam:CreateInstanceProfile",
                "iam:GetRole",
                "iam:UpdateAssumeRolePolicy",
                "iam:ListRoleTags",
                "iam:TagRole",
                "iam:CreateRole",
                "iam:DeleteRole",
                "iam:AttachRolePolicy",
                "iam:PutRolePolicy",
                "iam:AddRoleToInstanceProfile",
                "iam:ListInstanceProfilesForRole",
                "iam:DetachRolePolicy",
                "iam:ListAttachedRolePolicies",
                "iam:DeleteRolePolicy",
                "iam:ListAttachedGroupPolicies",
                "iam:ListRolePolicies",
                "iam:GetRolePolicy",
                "iam:PassRole",
                "iam:GetInstanceProfile",
                "iam:CreateUser",
                "iam:CreateAccessKey",
                "iam:DeleteAccessKey",
                "iam:PutUserPolicy",
                "iam:DeleteUserPolicy",
                "iam:GetUser",
                "iam:GetUserPolicy",
                "iam:ListAttachedUserPolicies",
                "iam:ListUserPolicies",
                "iam:UpdateLoginProfile",
                "iam:ListAccessKeys",
                "iam:AttachUserPolicy",
                "iam:DetachUserPolicy",
                "iam:CreateLoginProfile"
            ]
            Resource = [
                "arn:aws:iam::*:instance-profile/*",
                "arn:aws:iam::*:role/*",
                "arn:aws:iam::*:group/*",
                "arn:aws:iam::*:user/*"
            ]
        }
      ]
    })
  }
  
  inline_policy {
    name = "apono-read-resource-tags"
    policy = jsonencode({
      Version = "2012-10-17"
      Statement = [{
        "Effect": "Allow",
        "Action": [ "tag:GetResources" ],
        "Resource": "*"
      }]
    })
  }
    
  inline_policy {
    name = "ec2-policy"
    policy = jsonencode({
      Version = "2012-10-17"
      Statement = [{
        "Effect": "Allow",
        "Action": [ "ec2:DescribeInstances","ec2:DescribeTags","ec2:AssociateIamInstanceProfile" ],
        "Resource": "*"
      }]
    })
  }
}
```

### Validate the Connector is Connected

You can validate the Connector is installed in the [Connector status page](https://app.apono.io/connectors).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.apono.io/docs/kubernetes-environment/apono-connector-for-kubernetes/installing-a-connector-on-kubernetes-with-aws-permissions.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
