Deploy the image service¶
Same shape as every recipe in Phase-1 and Phase-2. Terraform composes the E1 baseline; each provider adds only what the image service actually needs — which is often nothing more than IAM.
Official docs verified 2026-08-08
- Azure OpenAI Terraform via
azurerm_cognitive_deployment(for the image deployment): registry.terraform.io/…/azurerm/latest/docs/resources/cognitive_deployment - Vertex Imagen access is granted via
roles/aiplatform.user(same role as chat + embeddings; no per-model resource needed). - Bedrock model access requires
bedrock:InvokeModelon the Nova Canvas ARN — see docs.aws.amazon.com/bedrock/latest/userguide/security_iam_id-based-policy-examples.
Layout¶
examples/image/
service/ # per-cloud text→image, one signature
generate.py # dispatch on CHIRON_PROVIDER
main.py # FastAPI /image (POST { prompt } -> PNG)
Dockerfile
requirements.txt
chart/ # Helm chart same shape as E2 + image env
Chart.yaml
values.yaml
templates/
deployment.yaml
service.yaml
serviceaccount.yaml
terraform/
azure/ (module "baseline" + IAM/deployment for image model)
gcp/ (module "baseline" + service account bound to aiplatform.user)
aws/ (module "baseline" + IAM policy allowing bedrock:InvokeModel on Nova Canvas)
Terraform — compose, add only IAM¶
module "baseline" {
source = "../../../foundations/azure"
name = var.name
region = var.region
compute = var.compute
}
# Reuse the Azure OpenAI account you already have (created in E2 by
# the shared portal). The image-model deployment is declared here so
# the recipe is one `terraform apply` from a working image service.
resource "azurerm_cognitive_deployment" "image" {
name = var.image_deployment_name # e.g. "gpt-image-1"
cognitive_account_id = var.azure_openai_account_id # from your existing OpenAI account
model {
format = "OpenAI"
name = var.image_model_name # "gpt-image-1"
version = var.image_model_version # e.g. "2024-10-01"
}
sku {
name = "GlobalStandard"
capacity = 1
}
}
module "baseline" {
source = "../../../foundations/gcp"
project_id = var.project_id
name = var.name
region = var.region
compute = var.compute
}
# Vertex Imagen uses the standard aiplatform.user role — same as chat.
resource "google_service_account" "image" {
account_id = "${var.name}-image"
display_name = "Chiron image service"
}
resource "google_project_iam_member" "image_aiplatform_user" {
project = var.project_id
role = "roles/aiplatform.user"
member = "serviceAccount:${google_service_account.image.email}"
}
module "baseline" {
source = "../../../foundations/aws"
name = var.name
region = var.region
compute = var.compute
}
data "aws_iam_policy_document" "nova_canvas_invoke" {
statement {
effect = "Allow"
actions = ["bedrock:InvokeModel"]
resources = [
"arn:aws:bedrock:*::foundation-model/amazon.nova-canvas-v1:0",
]
}
}
resource "aws_iam_policy" "nova_canvas_invoke" {
name = "${var.name}-nova-canvas-invoke"
policy = data.aws_iam_policy_document.nova_canvas_invoke.json
}
Helm — one small env block¶
Only the image-model IDs need env — every other lever (chat, embed, TTS) is unchanged from E2/P2.1.
helm upgrade --install image ./examples/image/chart \
--set image.repository="…/image" --set image.tag="v1" \
--set env.CHIRON_PROVIDER="azure" \
--set env.AZURE_IMAGE_DEPLOYMENT="gpt-image-1"
Verify (validate-only)¶
for p in azure gcp aws; do
( cd examples/image/terraform/$p && terraform init -backend=false && terraform validate )
done
helm lint examples/image/chart
helm template image examples/image/chart > /dev/null
python -m compileall examples/image/service
Live image generation needs real cloud accounts + model access; Phase 3 covers billed apply.