Self-hosted Veza (AWS VPC)

Learn about deploying Veza Enterprise SaaS on your own cloud infrastructure

Overview

Veza Enterprise SaaS is available for cloud-premises deployment within a customer-managed AWS Virtual Private Cloud (VPC). This option enables a fully isolated installation where all access to Veza is controlled within a customer's own AWS account and cloud infrastructure. A customer-managed deployment is often necessary for regulatory compliance in industry verticals such as financial services and healthcare.

To install and upgrade the self-hosted deployment, Veza support staff will coordinate with the enterprise customer to:

  • Decide on the appropriate level of external communication for logging and issue detection: To support the deployment, Veza expects to use a self-provided SOC2-compliant external logging tool, and restrictions on outbound logging and alerting communications will dramatically impact supportability. Network and security teams should agree on a policy for exporting data outside of the VPC environment.

  • Configure an AWS bastion host jump box: A virtual machine will enable a secure gateway for external access to the customer-managed VPC. The Veza team can initialize the VM, or work with the customer to start and configure the VM, which serves as the point of entry for Veza SaaS installation and upgrades. The bastion host jump box must be accessible by the Veza team by VPN or VPC peering.

  • Deploy Veza Enterprise SaaS: After configuring the bastion host, Veza staff will begin the deployment process within the AWS VPC and verify functionality before handing off to the customer.

  • Perform periodic upgrades and maintenance: After the initial deployment, Veza staff will access the bastion host to conduct routine upgrades. This includes applying patches, bug fixes, and other necessary updates. Veza follows a weekly release cadence. However, customers have the flexibility to delay updates during critical periods, for example, while an access review campaign is ongoing.

This document provides an overview of downloading and installing a custom Veza release in a production, staging, or QA environment using a Linux bastion host and a GitOps-based workflow. For additional guidance on evaluating and implementing Veza in customer-managed AWS VPC environments, please reach out to our sales engineering and customer success teams.

Deployment architecture

  • All access to the cluster is performed over HTTPS

  • Maintenance is done via the bastion accessed by SSH

  • All outbound webhooks are HTTP or HTTPS

  • Email is sent via SMTP, with credentials provided by the customer or set up in SES

  • All logs and alerting data is sent via HTTPS

  • Images essential to run the service are pulled from AWS ECR by assuming a read-only role in the production Veza AWS account. Veza does not mirror images to the customer account at release.

Self-hosted Veza FAQ

Question: Which version of Linux is recommended? Are there specific EC2 tech specs? is a separate AMI required?

Answer: There is no specific required version of Linux or Amazon Machine Image (AMI). It is only used for running the Veza deployer. We recommend using the latest version of Amazon Linux, Red Hat Enterprise Linux, or Ubuntu.

The deployer is tested on:

  • Amazon Linux 2 2.0.20230314

  • Red Hat Enterprise Linux 8.6

  • Ubuntu 22.04 LTS

Question: Is a specific Docker version required?

Answer: We recommend using Docker version 19.03.8, or the latest version installed with Amazon Linux. Docker CE or an equivalent may be used.

Question: Where is the Veza ECR located?

Answer: The ECR repository is in our production AWS account. You will be provided with the account ID and authorized to pull deployer images.

Question: Does Veza use AWS role ARNs or bespoke Kubernetes authentication?

Answer: Role ARNs, created and managed by the deployer using terraform.

Question: Do we need to provision an EKS cluster to install Veza?

Answer: No, the deployer automatically provisions and manages all resources, including an EKS cluster within your AWS account.

Question: Are automatic updates optional?

Answer: Updates are only applied at deploy time, which you can manage. For security and supportability reasons, you must deploy a new version of the software every 8 weeks.

Prerequisites

To use the deployer, customers must provide an AWS account and an AWS IAM role with the necessary permissions to create the required resources, including

  • A virtual private cloud (AWS VPC) with public and private subnets.

    • AWS ENI with private IPs for EKS pods.

  • Three AWS EC2 instance autoscaling groups, one per availability zone (AZ).

    • AWS Encrypted EBS + Snapshots.

  • AWS S3 bucket (Server side encrypted).

  • AWS Elastic Load Balancer (ELB) + WAF.

  • AWS Elastic Kubernetes Service (EKS).

  • AWS CloudWatch logs.

  • AWS Key Management Service (KMS) and AWS Certificate Manager (ACM).

  • AWS IAM roles (used to set up IAM roles and policies for EKS pods).

  • AWS NAT Gateway + Internet Gateway.

  • AWS Route53.

  • SMTP server or access to a configured AWS SES.

The example AWS IAM policy provided at the end of this document grants all the required permissions for running the Veza deployer.

Bastion host configuration

Self-hosted deployments incorporate a Linux bastion host that Veza employees or customer administrators can access for routine tasks, Veza installations, and upgrades. The bastion can be behind a VPN, or VPC peered with Veza's bastion network depending on the customer's security requirements.

Downloading a custom Veza build

The Veza support team will typically own the steps of downloading the deployer and installing from the jump box. This will involve the following steps:

Typical installation:

The Veza team publishes a link to each new release. To download the file and make it executable:

  1. Log in to the bastion host for the environment to upgrade

  2. Download the custom build: wget -O veza-{{VERSION}} "<<link>>"

  3. Make the file executable: chmod +x veza-{{VERSION}}

  4. Move it to the "deployments" folder: mv veza-{{VERSION}} deployments/ && cd deployments

Note that build links expire after 12 hours.

Typical maintenance:

A configuration manifest stores all deployment parameters. The Veza team will typically supply a custom configuration file based on the desired environment. You can specify the configuration to use with the '-c' or '--config' flag, for example:

  1. Extract ./veza-{{VERSION}} -c config.yaml extract

  2. Install ./veza-{{VERSION}} -c config.yaml install all --skip-image-pull.

Example AWS IAM policy - Veza deployer

The deployer will need an AWS IAM role granting the following permissions to create and configure AWS resources:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ReadCreateDelete",
      "Effect": "Allow",
      "Action": [
        "access-analyzer:ValidatePolicy",
        "acm:*",
        "acm:AddTagsToCertificate",
        "acm:DescribeCertificate",
        "acm:ImportCertificate",
        "acm:ListTagsForCertificate",
        "autoscaling:AttachLoadBalancerTargetGroups",
        "autoscaling:DescribeAutoScalingGroups",
        "autoscaling:DetachLoadBalancerTargetGroups",
        "ec2:*",
        "ecr:BatchGetImage",
        "ecr:GetAuthorizationToken",
        "ecr:GetDownloadUrlForLayer",
        "eks:*",
        "elasticloadbalancing:*",
        "iam:AddRoleToInstanceProfile",
        "iam:AttachRolePolicy",
        "iam:CreateInstanceProfile",
        "iam:CreateOpenIDConnectProvider",
        "iam:CreatePolicy",
        "iam:CreateRole",
        "iam:CreateServiceLinkedRole",
        "iam:DeleteInstanceProfile",
        "iam:DeleteOpenIDConnectProvider",
        "iam:DeletePolicy",
        "iam:DeleteRole",
        "iam:DeleteRolePolicy",
        "iam:DetachRolePolicy",
        "iam:GetOpenIDConnectProvider",
        "iam:GetPolicy",
        "iam:GetPolicyVersion",
        "iam:GetRole",
        "iam:GetRolePolicy",
        "iam:ListAttachedRolePolicies",
        "iam:ListInstanceProfilesForRole",
        "iam:ListPolicies",
        "iam:ListPolicyVersions",
        "iam:ListRolePolicies",
        "iam:ListRoles",
        "iam:PassRole",
        "iam:PutRolePolicy",
        "iam:RemoveRoleFromInstanceProfile",
        "iam:Tag*",
        "iam:Untag*",
        "iam:UpdateAssumeRolePolicy",
        "kms:CreateAlias",
        "kms:CreateGrant",
        "kms:CreateKey",
        "kms:DeleteAlias",
        "kms:DescribeKey",
        "kms:GetKeyPolicy",
        "kms:GetKeyRotationStatus",
        "kms:ListAliases",
        "kms:ListResourceTags",
        "kms:ScheduleKeyDeletion",
        "kms:TagResource",
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:DeleteLogGroup",
        "logs:DeleteLogStream",
        "logs:DeleteRetentionPolicy",
        "logs:DescribeLogGroups",
        "logs:DescribeLogStreams",
        "logs:ListTagsLogGroup",
        "logs:PutRetentionPolicy",
        "logs:TagLogGroup",
        "logs:UntagLogGroup",
        "route53:ChangeTagsForResource",
        "route53:CreateHostedZone",
        "route53:GetChange",
        "route53:GetHostedZone",
        "route53:ListHostedZones",
        "route53:ListResourceRecordSets",
        "route53:ListTagsForResource",
        "route53:UpdateHostedZoneComment",
        "s3:CreateBucket",
        "s3:DeleteBucketPolicy",
        "s3:GetBucketPolicy",
        "s3:GetBucketPolicyStatus",
        "s3:GetBucketTagging",
        "s3:ListBucket",
        "s3:PutBucketPolicy",
        "s3:PutEncryptionConfiguration",
        "sts:AssumeRole",
        "sts:GetCallerIdentity",
        "wafv2:AssociateWebACL",
        "wafv2:CheckCapacity",
        "wafv2:CreateWebACL",
        "wafv2:DeleteWebACL",
        "wafv2:DescribeManagedRuleGroup",
        "wafv2:DisassociateWebACL",
        "wafv2:GetWebACL",
        "wafv2:GetWebACLForResource",
        "wafv2:ListAvailableManagedRuleGroups",
        "wafv2:ListTagsForResource",
        "wafv2:ListWebACLs",
        "wafv2:UpdateWebACL"
      ],
      "Resource": "*"
    },
    {
      "Sid": "WriteOrDelete",
      "Effect": "Allow",
      "Action": [
        "acm:DeleteCertificate",
        "acm:RemoveTagsFromCertificate",
        "ec2:DeleteClientVpnEndpoint",
        "ec2:DeleteInternetGateway",
        "ec2:DeleteKeyPair",
        "ec2:DeleteNatGateway",
        "ec2:DeleteRoute",
        "ec2:DeleteRouteTable",
        "ec2:DeleteSecurityGroup",
        "ec2:DeleteSubnet",
        "ec2:DeleteTags",
        "ec2:DeleteVpc",
        "ec2:DetachInternetGateway",
        "ec2:DetachNetworkInterface",
        "ec2:DisassociateAddress",
        "ec2:DisassociateClientVpnTargetNetwork",
        "ec2:DisassociateRouteTable",
        "ec2:ModifyClientVpnEndpoint",
        "ec2:ModifyNetworkInterfaceAttribute",
        "ec2:ModifySubnetAttribute",
        "ec2:ModifyVpcAttribute",
        "ec2:ReleaseAddress",
        "ec2:ReplaceRoute",
        "ec2:ReplaceRouteTableAssociation",
        "ec2:RevokeClientVpnIngress",
        "ec2:RevokeSecurityGroupEgress",
        "ec2:RevokeSecurityGroupIngress",
        "ec2:UpdateSecurityGroupRuleDescriptionsEgress",
        "ec2:UpdateSecurityGroupRuleDescriptionsIngress"
      ],
      "Resource": "*",
      "Condition": {
        "StringLike": {
          "aws:ResourceTag/owner": [
            "veza",
            "<<cluster-name>>"
          ]
        }
      }
    },
    {
      "Sid": "ELBModify",
      "Effect": "Allow",
      "Action": [
        "elasticloadbalancing:DeleteLoadBalancer",
        "elasticloadbalancing:ModifyLoadBalancerAttributes",
        "elasticloadbalancing:RemoveTags",
        "elasticloadbalancing:SetSecurityGroups"
      ],
      "Resource": [
        "arn:aws:elasticloadbalancing:*:*:loadbalancer/app/<<cluster-name>>*/*"
      ]
    },
    {
      "Sid": "ELBListenersWrite",
      "Effect": "Allow",
      "Action": [
        "elasticloadbalancing:AddListenerCertificates",
        "elasticloadbalancing:DeleteListener",
        "elasticloadbalancing:ModifyListener",
        "elasticloadbalancing:RemoveListenerCertificates"
      ],
      "Resource": [
        "arn:aws:elasticloadbalancing:*:*:listener/app/<<cluster-name>>*/*/*"
      ]
    },
    {
      "Sid": "ELBListenerRulesModify",
      "Effect": "Allow",
      "Action": [
        "elasticloadbalancing:CreateRule",
        "elasticloadbalancing:DeleteRule",
        "elasticloadbalancing:ModifyRule",
        "elasticloadbalancing:SetRulePriorities"
      ],
      "Resource": [
        "arn:aws:elasticloadbalancing:*:*:listener/app/<<cluster-name>>*/*/*",
        "arn:aws:elasticloadbalancing:*:*:listener-rule/app/<<cluster-name>>*/*/*/*"
      ]
    },
    {
      "Sid": "ELBTargetGroupsModify",
      "Effect": "Allow",
      "Action": [
        "elasticloadbalancing:DeleteTargetGroup",
        "elasticloadbalancing:DeregisterTargets",
        "elasticloadbalancing:ModifyTargetGroup",
        "elasticloadbalancing:ModifyTargetGroupAttributes"
      ],
      "Resource": [
        "arn:aws:elasticloadbalancing:*:*:targetgroup/cai443*/*",
        "arn:aws:elasticloadbalancing:*:*:targetgroup/cai80*/*",
        "arn:aws:elasticloadbalancing:*:*:targetgroup/http2*/*"
      ]
    },
    {
      "Sid": "S3Objects",
      "Effect": "Allow",
      "Action": [
        "s3:DeleteObject",
        "s3:DeleteObjectVersion",
        "s3:GetObject",
        "s3:GetObjectTagging",
        "s3:PutObject",
        "s3:PutObjectTagging"
      ],
      "Resource": [
        "arn:aws:s3:::<<cluster-name>>*/*"
      ]
    }
  ]
}

Last updated