Apigee X Organization Provisioning with Google Terraform Modules

Edit (December 2022): Please note that the cloud foundation fabric modules introduced a new consolidated Apigee module. The code in this post will still work since the versions are pinned but you might want to check out the new Apigee module with additional capabilities. 

There are a number of ways to provision an Apigee X (trial) organization. The official documentation describes how to provision an Apigee instance through an interactive wizard, by following a number of CLI commands or by using the provisioning script from the Apigee devrel community repository.

In this short post we introduce a terraform-based option that makes use of the google terraform provider as well as new Apigee cloud foundation terraform modules.

Note: The dependencies to the cloud foundation fabric resources are pinned to a specific release tag. Please check the upstream repository for the latest tags.

 

Apigee X - Evaluation Org Provisioning

To prepare your GCP project for running the terraform script, you’ll have to enable the following Google APIs:

  • apigee.googleapis.com
  • compute.googleapis.com
  • servicenetworking.googleapis.com

You can do this by running the following command:

 

 

PROJECT_ID=my-project-id

gcloud services enable compute.googleapis.com apigee.googleapis.com servicenetworking.googleapis.com --project $PROJECT_ID

 

 

Once the APIs are enabled, we can start preparing our script.

 

The core of the script is represented by the invocation of the two Apigee terraform modules as well as the terraform module to prepare your service networking that is used to peer your tenant project with your own VPC. To do this we can create our own main.tf file and add the following content:

 

 

// main.tf

module "vpc" {
  source     = "github.com/terraform-google-modules/cloud-foundation-fabric//modules/net-vpc?ref=v14.0.0"
  project_id = var.project_id
  name       = var.network
  psa_ranges = {
   apigee-range = var.peering_range
  }
}

module "apigee" {
  source              = "github.com/terraform-google-modules/cloud-foundation-fabric//modules/apigee-organization?ref=v14.0.0"
  project_id          = var.project_id
  analytics_region    = var.analytics_region
  runtime_type        = "CLOUD"
  authorized_network  = module.vpc.network.id
  apigee_environments = var.apigee_environments
  apigee_envgroups    = var.apigee_envgroups
}

module "apigee-x-instance" {
  source              = "github.com/terraform-google-modules/cloud-foundation-fabric//modules/apigee-x-instance?ref=v14.0.0"
  apigee_org_id       = module.apigee.org_id
  name                = "my-eval-instance"
  region              = var.runtime_region
  ip_range            = var.instance_cidr
  apigee_environments = var.apigee_environments
}

 

 

For reusability, we decided to make use of a few terraform variables which we need to declare in a separate variables.tf file:

 

 

// variables.tf

variable "analytics_region" {
  description = "Analytics Region for the Apigee Organization (immutable). See https://cloud.google.com/apigee/docs/api-platform/get-started/install-cli."
  type = string
}

variable "apigee_envgroups" {
  description = "Apigee Environment Groups."
  type = map(object({
    environments = list(string)
    hostnames    = list(string)
  }))
  default = {}
}

variable "apigee_environments" {
  description = "Apigee Environment Names."
  type        = list(string)
  default     = []
}

variable "network" {
  description = "Name of the VPC network to be created."
  type        = string
}

variable "peering_range" {
  description = "RFC CIDR range for service network peering."
  type        = string
}

variable "project_id" {
  description = "Project ID to host this Apigee organization (will also become the Apigee Org name)."
  type        = string
}

variable "runtime_region" {
  description = "Apigee Runtime Instance Region."
  type        = string
}

variable "instance_cidr" {
  description = "CIDR Block to be used by the Apigee instance."
  type        = string
}

 

 

With these we can declare all our configuration values in a my-x-eval.tfvars file:

 

 

// my-x-eval.tfvars

peering_range = "10.0.0.0/21"
instance_cidr = "10.0.0.0/22
network = "apigee-vpc"
analytics_region = "europe-west1"
runtime_region = "europe-west6"
apigee_environments = ["eval1", "eval2"]
apigee_envgroups = {
  eval = {
    environments = ["eval1", "eval2"]
    hostnames    = ["eval.api.example.com"]
  }
}

 

 

Within the folder where you created the three files above you can then initialize your terraform module and inspect the generated plan:

 

 

terraform init
terraform plan --var-file="my-x-eval.tfvars" -var=project_id=$PROJECT_ID

 

 

This should display the full plan and the total resources that should be created:

...
Plan
: 12 to add, 0 to change, 0 to destroy.

If you are happy with the plan, you can provision your org like this:

 

 

terraform apply --var-file="my-x-eval.tfvars" -var=project_id=$PROJECT_ID

 

 

Please note that the instance creation itself can take anywhere between 15-25 min plus the time to provision the environments for the first time.
Once the deployment is completed you should see a message saying:

Apply complete! Resources: 12 added, 0 changed, 0 destroyed.

 

To find out the private endpoint for your Apigee instance you can either check the Admin > Instances page in the Apigee UI. Or run the following command:

 

 

TOKEN=$(gcloud auth print-access-token) 
curl -H "Authorization: Bearer $TOKEN" \ 
  https://apigee.googleapis.com/v1/organizations/$PROJECT_ID/instances

 

 

 

Apigee X - Paid Org Provisioning

The modules described above can also be used to provision paid Apigee X organizations. To create a paid organization you will have to adjust the peering CIDR mask to be of size 16 or 20 and add your KMS keys as described in the module documentation.

 

(Bonus) Apigee hybrid - Control Plane Provisioning

The apigee-organization terraform module can also be used to create an Apigee hybrid organization and its associated environments. Note that the terraform module only covers the installation of the control plane. For installing the runtime we suggest you follow the official runtime installation instructions. For this we enable the required google services:

 

 

PROJECT_ID=my-project-id
gcloud services enable apigee.googleapis.com --project $PROJECT_ID

 

 

create the following resources similar to the previous Apigee X example:

 

 

// main.tf

module "apigee" {
  source              = "github.com/terraform-google-modules/cloud-foundation-fabric//modules/apigee-organization?ref=v14.0.0"
  project_id          = var.project_id
  analytics_region    = var.analytics_region
  runtime_type        = "HYBRID"
  apigee_environments = var.apigee_environments
  apigee_envgroups    = var.apigee_envgroups
}
// variables.tf

variable "analytics_region" {
  description = "Analytics Region for the Apigee Organization (immutable). See https://cloud.google.com/apigee/docs/api-platform/get-started/install-cli."
  type = string
}

variable "apigee_envgroups" {
  description = "Apigee Environment Groups."
  type = map(object({
    environments = list(string)
    hostnames    = list(string)
  }))
  default = {}
}

variable "apigee_environments" {
  description = "Apigee Environment Names."
  type        = list(string)
  default     = []
}

variable "project_id" {
  description = "Project ID to host this Apigee organization (will also become the Apigee Org name)."
  type        = string
}
​
// my-hybrid-eval.tfvars

analytics_region = "us-central1"
apigee_environments = ["eval1", "eval2"]
apigee_envgroups = {
  eval = {
    environments = ["eval1", "eval2"]
    hostnames    = ["eval.api.example.com"]
  }
}

 

 

 

Similarly to the Apigee X example, we want to initialize, plan, and ultimately apply our terraform script.

 

 

terraform init
terraform plan --var-file="my-hybrid-eval.tfvars" -var=project_id=$PROJECT_ID
terraform apply --var-file="my-hybrid-eval.tfvars" -var=project_id=$PROJECT_ID

 

 

 

We can then create another terraform script to create the Kubernetes cluster in the desired provider and install the runtime accordingly. 

13 7 9,195
7 REPLIES 7

Thanks for sharing this. One thing I found is that I needed to add a depends_on between the instance and environment. Without this I had a race conditions/error when adding environments to the list. The instance create was already done, so it only had to create the attachment which would happen faster than env creation.

Hi @strebel ,

@joea (who is having a problem posting) is wondering...

Are you also working on example terraform modules for the Apigee Hybrid runtime plane and/or if this is not something he would recommend? If not, why?

Thanks!

Hi Paul, as long as the supported installation is based on the apigeectl cli and the overrides file, I'd recommend staying on the supported path and use tf only for infrastructure and Apigee hybrid control plane provisioning. You could of course also wrap the apigeectl execution in a local exec module but this isn't a recommended practice and raises additional questions for upgrade scenarios.

We deployed using terraform, but only the organization, environments and instances in APIGEE X were made available.

In our GCP project, no VMs, instance groups or Load Balancers were created. Is this really not created automatically?

Hi @strebel 

How to create Apigee PAYG org? It always creates evaluation version. I tried with billing_type PAYG,still it creates evaluation version.

Is it possible to create PAYG using terraform modules?

Hi

i was able to resolve it, but the env type is alwasys base.how to set the env type to standard?

Is there any example to do organization provisioning trough terraform with data residency? 

what will be the difference?, I’m sending all the necessary attributes. But my organization is still living in a global context.