Provision API hub

Stay organized with collections Save and categorize content based on your preferences.

You're viewing Apigee X documentation.
View Apigee Edge documentation.

This section describes how to provision the Apigee API hub using APIs. The following topics are discussed:

Define environment variables

Using environment variables ensures consistency and makes it easier for you to follow along in the documentation in later steps.

  1. Define the following environment variables, replacing the dynamic variables with your actual values:
    export TOKEN=$(gcloud auth print-access-token)
    
    # ----- Set key_ring_name and key_name to values that will help you identify the API hub encryption key in future. -----
    export KEY_RING_NAME=YOUR_KEY_RING_NAME
    export KEY_NAME=YOUR_KEY_NAME
    
    export PROJECT_ID=YOUR_PROJECT_ID
    export RUNTIME_LOCATION=YOUR_RUNTIME_LOCATION
    
    # -----If you already have a CMEK, define this environment variable-----
    export CMEK_KEY_ID=YOUR_CMEK_KEY_ID
    

    Where:

    • TOKEN is the token that authenticates and authorizes your calls to the Apigee Registry APIs. It should be passed in Authentication headers as a bearer token. Note that the token expires after a period of time and when it does, you can simply regenerate it using the same command. For more information, see the reference page for the print-access-token command.
    • KEY_RING_NAME is the name of the key ring you will use to identify your encryption key ring.
    • KEY_NAME is the name of the key you will use to identify your API hub encryption key.
    • PROJECT_ID is the Cloud project ID that you created as part of Prerequisites.
    • RUNTIME_LOCATION is the physical location where the Apigee Registry instance you will create later is located. The CMEK key needs to be in same region as the runtime location.

    • CMEK_KEY_ID is the key ID of your customer-managed encryption key. Key rotation is not currently supported.

      The key ID has the following syntax (similar to a file path):

      projects/PROJECT_ID/locations/RUNTIME_LOCATION/keyRings/KEY_RING_NAME/cryptoKeys/KEY_NAME
      
  2. (Optional) Check your work by echoing the values you just set. Note that when you want to use a variable in your commands, precede the variable's name with a dollar sign ($).
    echo $TOKEN
    echo $KEY_RING_NAME
    echo $KEY_NAME
    echo $PROJECT_ID
    echo $RUNTIME_LOCATION
    
    # -----If you already have a CMEK-----
    echo $CMEK_KEY_ID
    
    

Create service account and CMEK

This section describes how to create a service account and an encryption key ring and key.

  1. Create an Apigee Registry per-product per-project service account for your project:

    gcloud beta services identity create --service=apigeeregistry.googleapis.com --project=$PROJECT_ID
    

    The service account returned is similar to the following:

    service-755582297973@gcp-sa-apigeeregistry.iam.gserviceaccount.com
    
  2. Put the created service account in a variable:

    export SERVICE_ACCOUNT=YOUR_SERVICE_ACCOUNT
    
  3. Create a CMEK using KMS by following the steps below or use an existing KMS key. The CMEK key needs to be in same region as the runtime location.

    1. Create a keyring:

      gcloud kms keyrings create $KEY_RING_NAME \
        --location $RUNTIME_LOCATION \
        --project $PROJECT_ID
      
    2. Create a key:

      gcloud kms keys create $KEY_NAME \
        --keyring $KEY_RING_NAME \
        --location $RUNTIME_LOCATION \
        --purpose "encryption" \
        --project $PROJECT_ID
      
    3. Verify that the key was created. Key creation may take a few minutes to complete. If this command returns an empty list, wait and try again. When the key appears, you can proceed to the next step:

      gcloud kms keys list \
        --keyring $KEY_RING_NAME \
        --location $RUNTIME_LOCATION \
        --project $PROJECT_ID
      

      The key returned is similar to the following:

      projects/my-project/locations/us-west1/keyRings/my-key-ring-name/cryptoKeys/my-key-name
      
    4. Put the created key in a variable:

      export CMEK_KEY_ID="projects/PROJECT_ID/locations/RUNTIME_LOCATION/keyRings/KEY_RING_NAME/cryptoKeys/KEY_NAME
      
  4. Grant permission for service account on the CMEK:

    gcloud kms keys add-iam-policy-binding $KEY_NAME \
      --location $RUNTIME_LOCATION \
      --keyring $KEY_RING_NAME \
      --member serviceAccount:$SERVICE_ACCOUNT \
      --role roles/cloudkms.cryptoKeyEncrypterDecrypter \
      --project $PROJECT_ID
    
    
  5. Verify your service account has roles/cloudkms.cryptoKeyEncrypterDecrypter permission on the CMEK.

    gcloud kms keys get-iam-policy $CMEK_KEY_ID
    

Create instance

In this section, you will create a single instance of API hub. There can be only one instance per project.

Sample request

curl https://apigeeregistry.googleapis.com/v1/projects/$PROJECT_ID/locations/$RUNTIME_LOCATION/instances?instance_id=default \
  -X POST \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  --data-raw '{
    "config": {
      "cmek_key_name": "'"$CMEK_KEY_ID"'"
  }
}'

Sample response

{
  "name": "projects/my-project/locations/us-central1/operations/operation-1646987534895-5d9ed2af7889a-b4d376e8-14964abc",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.apigeeregistry.v1.OperationMetadata",
    "createTime": "2022-03-11T08:32:14.950522187Z",
    "target": "projects/my-project/locations/us-central1/instances/default",
    "verb": "create",
    "requestedCancellation": false,
    "apiVersion": "v1"
  },
  "done": false
}

Common errors - bad input data

HTTP status code: 400 Bad Request
Error message: Instance is a singleton, and instance_id must be set to "default".
Possible cause: Setting instance_id to anything other than default.
Solution: Use default as your instance_id.
HTTP status code: 400 Bad Request
Error message: global is not a supported location to create Instance.
Possible cause: Setting global as location.
Solution: Use one of the supported runtime locations listed above.
HTTP status code: 401 Unauthorized
Error message: Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential.
Possible cause: Inavlid Auth Token.
Solution: The request token may be ill-formatted or expired. Regenerate auth token by running token="$(gcloud auth print-access-token)" and pass Authorization: Bearer ${token} as header.
HTTP status code: 403 PERMISSION_DENIED
Error message: Location RUNTIME_LOCATION is not found or access is unauthorized.
Possible cause: Setting location to an unsupported location.
Solution: Use one of the supported runtime locations listed above.
HTTP status code: 400 Bad Request
Error message: Instance.config.cmek_key_name must be provided to create Instance.
Possible cause: cmek_key_name is not provided in data.
Solution: Provide CMEK name. See Create service account and CMEK for detailed instructions.
HTTP status code: 400 Bad Request
Error message: Invalid key format: a valid key should be in the form of projects/PROJECT/locations/us-central1/keyRings/KEYRING/cryptoKeys/CRYPTOKEY.
Possible cause: cmek_key_name is ill-formatted.
Solution: Correct the key format.
HTTP status code: 400 Bad Request
Error message: CMEK key location needs to match the location of instance creation.
Possible cause: CMEK is in a different location.
Solution: Correct the location of the CMEK.
HTTP status code: 400 Bad Request
Error message: Apigee Registry service account must have roles/cloudkms.cryptoKeyEncrypterDecrypter permission on the CMEK key.
Possible cause: Apigee service account lacks permission on the CMEK. Note that we know only that the service account doesn't have the necessary permission. It's probable that the key doesn't exist at all, but we can't tell.
Solution: Verify that the key exists and that Apigee Registry service account has the required permission on the key.

Common errors - bad state

HTTP status code: 400 Bad Request
Error message:

If instance is active:

Instance is ACTIVE at SOME_LOCATION. It cannot be created again.

If instance is other than active state:

Instance has state STATE at SOME_LOCATION. It cannot be created.

Possible cause: Calling this API when an instance is already present or being created at some location.
Solution: Ignore the error if this API is triggered by mistake. If it is a legitimate call and you indeed want to create an instance at this location, call DeleteInstance first, at the current instance location.

Get instance

This section describes how to get details (region, state, etc.) about the API hub Runtime Instance associated with your project.

Sample request

curl https://apigeeregistry.googleapis.com/v1/projects/$PROJECT_ID/locations/$RUNTIME_LOCATION/instances/default \
  -X GET \
  -H "Authorization: Bearer $TOKEN"

Sample response - instance creation in progress

{
  "name": "projects/my-project/locations/us-central1/instances/default",
  "createTime": "2022-03-11T08:32:14.944703257Z",
  "updateTime": "2022-03-11T08:32:14.944703257Z",
  "state": "CREATING",
  "stateMessage": "Creating instance...\nDetails: projects/PROJECT_ID/locations/RUNTIME_LOCATION/operations/operation-1646987534895-5d9ed2af7889a-b4d376e8-14964abc",
  "config": {
    "location": "us-central1",
    "cmekKeyName": "projects/PROJECT/locations/RUNTIME_LOCATION/keyRings/KEYRING/cryptoKeys/KEY""
  }
}

Sample response - instance creation complete

{
  "name": "projects/myproject/locations/us-central1/instances/default",
  "createTime": "2022-03-11T08:32:14.944703257Z",
  "updateTime": "2022-03-11T08:56:31.087709218Z",
  "config": {
    "location": "us-central1",
    "cmekKeyName": "projects/my-project/locations/us-central1/keyRings/apihub-key-ring/cryptoKeys/apihub-key"
  },
  "state": "ACTIVE",
  "stateMessage": "Instance is active and ready to use."
}

Common errors

HTTP status code: 404 Not Found
Error message: Resource was not found.
Possible cause: Calling this API at a location where an instance does not exist.
Solution: Call the CreateInstance API before calling the GetInstance API at the location where you want to create the Instance. If the Instance has been created but you don't know the location, call CreateInstance API at any location, which fails with a message that provides a hint on the Instance location.

Delete instance

This section describes how to delete an instance.

Sample request

curl https://apigeeregistry.googleapis.com/v1/projects/$PROJECT_ID/locations/$RUNTIME_LOCATION/instances/default \
  -X DELETE \
  -H "Authorization: Bearer $TOKEN"

Sample response

{
  "name": "projects/my-project/locations/us-central1/operations/operation-1646987534895-5d9ed2af7889a-b4d376e8-14964abc",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.apigeeregistry.v1.OperationMetadata",
    "createTime": "2022-03-11T08:32:14.950522187Z",
    "target": "projects/my-project/locations/us-central1/instances/default",
    "verb": "delete",
    "apiVersion": "v1"
  },
  "done": false
}

Common errors

HTTP status code: 404 Not Found
Error message: Resource was not found.
Possible cause: Calling this API at a location where an instance does not exist.
Solution: Call DeleteInstance only at the location where instance is ACTIVE or FAILED.
HTTP status code: 400 Bad Request
Error message: Instance must be ACTIVE or FAILED to be deleted. Current state: STATE.
Possible cause: Calling this API at a location where the instance state is not ACTIVE or FAILED.
Solution: Call DeleteInstance only at the location where instance is ACTIVE or FAILED.

Get operation

This section describes how to check the operation status. When operations take a long time to complete (LROs), the API returns an operation ID. Calling GetOperation using the operation ID returns the operation status.

Sample request

curl https://apigeeregistry.googleapis.com/v1/projects/$PROJECT_ID/locations/$RUNTIME_LOCATION/operations/OPERATION_ID \
  -X GET \
  -H "Authorization: Bearer $TOKEN"

Where OPERATION_ID is a value returned for LROs as explained in Create instance, and is in the form operation-1650479361714-5dd1a2c1068bf-464fac6b-18eeb734.

Sample response - instance creation in progress

{
  "name": "projects/my-project/locations/us-central1/operations/operation-1646987534895-5d9ed2af7889a-b4d376e8-14964abc",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.apigeeregistry.v1.OperationMetadata",
    "createTime": "2022-03-11T08:32:14.950522187Z",
    "target": "projects/my-project/locations/us-central1/instances/default",
    "verb": "create",
    "requestedCancellation": false,
    "apiVersion": "v1"
  },
  "done": false
}

Sample response - instance creation complete

{
  "name": "projects/my-project/locations/us-central1/operations/operation-1646987534895-5d9ed2af7889a-b4d376e8-14964abc",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.apigeeregistry.v1.OperationMetadata",
    "createTime": "2022-03-11T08:32:14.950522187Z",
    "endTime": "2022-03-11T08:56:31.069701960Z",
    "target": "projects/my-project/locations/us-central1/instances/default",
    "verb": "create",
    "requestedCancellation": false,
    "apiVersion": "v1"
  },
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.cloud.apigeeregistry.v1.Instance",
    "name": "projects/my-project/locations/us-central1/instances/default",
    "createTime": "2022-03-11T08:32:14.944703257Z",
    "updateTime": "2022-03-11T08:56:31.069701960Z",
    "config": {
      "location": "us-central1",
      "cmekKeyName": ""projects/PROJECT/locations/RUNTIME_LOCATION/keyRings/KEYRING/cryptoKeys/KEY""
    },
    "state": "ACTIVE",
    "stateMessage": "Instance is active and ready to use."
  }
}

Sample response - instance deletion complete

{
  "name": "projects/my-project/locations/us-east1/operations/operation-1647669637561-5da8bfb743b86-4af586a4-83c04472",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.apigeeregistry.v1.OperationMetadata",
    "createTime": "2022-03-19T06:00:38.046462309Z",
    "endTime": "2022-03-19T06:01:01.382751041Z",
    "target": "projects/my-project/locations/us-east1/instances/default",
    "verb": "delete",
    "apiVersion": "v1"
  },
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.protobuf.Empty"
  }
}

What's next