DEV Community

Cover image for Using KIRO and AMDF MCP to Build Reusable Kubernetes KRO Packages

Using KIRO and AMDF MCP to Build Reusable Kubernetes KRO Packages

Continuing our journey with KCL, in this post we will explore how to accelerate the creation of reusable Kubernetes packages from CRDs using KIRO and the AMDF MCP tool.

Kiro + AMDF MCP elevate a process that traditionally requires long times in a conversation of minutes, where the developer simply indicates what resources are needed.

Additionally, by using KCL instead of traditional YAML, KCL provides strong typing, validation at development time, and abstraction capabilities that transform repetitive configurations into reusable and maintainable code. The result is infrastructure as data that is not only generated quickly, but is also robust, validated, and ready.

Prerequisites

KRO-ACK-ESO CRDS

Step 1.

Validate your CRDS.
In this case the cluster have CRDS from ESO and ACK EC2-RDS Controllers.

EC2 ACK Controllers

Kro CRDS

Step 2.

Connect MCP.
With AMDF installed is so simple like as execute

amdf mcp-server 
Starting AMDF MCP Server...
Enter fullscreen mode Exit fullscreen mode

Step 3.

With the MCP Server running, open KIRO for start to create reusable packages using a basic prompt.

Kiro, I need to create a ResourceGraphDefinition CRD KCL schema for generate an abstraction of multiple resources.

KIRO Prompt KCL

Step 4.

With the prompt running, the AMDF MCP tools start to working.

KIRO PROMPT AMDF MCP SERVER

KIRO PROMPT KCL AMDF

Step 5.

AMDF Automatically create this directorys using KCL sintax.

AMDF MCP SCALLFODER description

Step 6.

For this demo, I migrated a code from crossplane to KRO, using
helper functions and CEL expretions required for KRO.

Check the code in this repository

GitHub logo segoja7 / mcp-kcl-infra-accelerator

Kubernetes packages using KRO, KCL, and MCP (KIRO + AMDF).

Keycloak Stack

A reusable Keycloak deployment abstraction built with KRO and KCL. It provisions Keycloak and its database backend — either a local PostgreSQL instance or AWS RDS — from a single Kubernetes custom resource.

Architecture

Keycloak Stack Architecture

Description

This example demonstrates how to use KCL to define a KRO ResourceGraphDefinition that generates a KeycloakStack CRD. Applying a KeycloakStack instance creates all the necessary Kubernetes resources for a fully functional Keycloak deployment.

The stack supports two deployment modes controlled by the localTest flag:

  • Local mode (localTest: true) — Deploys an in-cluster PostgreSQL Deployment, Service, and Secret. Ideal for development and testing.
  • AWS RDS mode (localTest: false) — Provisions an AWS RDS DBInstance with optional subnet group and security group, and connects Keycloak via an ExternalName Service. Supports three password management strategies.

Project Structure


├── KRO-KEYCLOAK-1.drawio.png          # Architecture diagram
├── kcl_render/
│   └── KeycloakStack.yaml             # Rendered YAML output

Step 7.

Check the Main.k
New to KCL? Don't worry! The syntax is designed to be developer-friendly. You can find a complete introduction in my previous blog

Is time for test that code is correctly and compile.

kcl library/main.k

Step 8.

Test that new KCL package using AMDF, KIRO and RDS, EC2 ACK and External Secrets Controllers are working correctly.

kcl library/main.k | kubectl apply -f -
resourcegraphdefinition.kro.run/keycloak-stack created
Enter fullscreen mode Exit fullscreen mode

Here's an RGD that creates a new KeycloakStack API. When users create an KeycloakStack, kro automatically creates multiples resources defined in the Resource Graph Definition

resource graph definition kro

For now, this is a local test, but let me show you how to bring this to GitOps and integrate it with OCI registries and using the KCL plugin for deployment in the next blog.

Step 9.

check the 02-aws-rds-deploy.yaml.

apiVersion: kro.run/v1alpha1
kind: KeycloakStack
metadata:
  name: keycloak-dev
  namespace: default
spec:
  projectName: "dev"
  environment: "dev"
  keycloakMode: "start-dev"
  keycloakReplicas: 1
  kcProxy: ""  # Sin proxy para port-forward  
  keycloakImage: "quay.io/keycloak/keycloak:latest"
  keycloakAdminUser: "admin"
  keycloakHostname: "keycloakrds.local"
  postgresImage: "postgres:17"
  postgresPassword: ""
  localTest: false
  rdsInstanceClass: "db.t3.micro"
  rdsAllocatedStorage: 20
  rdsEngineVersion: "17"
  rdsDBName: "keycloak"
  rdsUsername: "keycloak"
  rdsManageMasterUserPassword: true 
  rdsSubnetIDs:
    - "subnet-0436a5657992422d2"  # us-east-1a - CAMBIAR
    - "subnet-03fc372cafad1feec"  # us-east-1b - CAMBIAR
  rdsVPCID: "vpc-0d7e4425ca4d23f89"  # CAMBIAR
  rdsAllowedCIDRs:
    - "10.0.0.0/16"  # CIDR de tu VPC
Enter fullscreen mode Exit fullscreen mode

Apply the KeycloakStack yaml resource for deploy and test.

kubectl apply -f sample/02-aws-rds-deploy.yaml 
keycloakstack.kro.run/keycloak-dev created
Enter fullscreen mode Exit fullscreen mode

Step 10.

Validate that resources are ready.

kubectl get keycloakstack,dbsubnetgroups,securitygroups,dbinstances,secretstore,externalsecret,secrets,svc,deployments,pods,ingress -n default

NAME                                 STATE    READY   AGE
keycloakstack.kro.run/keycloak-dev   ACTIVE   True    11m

NAME                                                           AGE
dbsubnetgroup.rds.services.k8s.aws/keycloak-subnet-group-dev   11m

NAME                                                     ID
securitygroup.ec2.services.k8s.aws/keycloak-rds-sg-dev   sg-0bae8ee9ebb07ac3b
securitygroup.ec2.services.k8s.aws/my-webserver-sg       sg-06db013ac4841cf58

NAME                                               STATUS
dbinstance.rds.services.k8s.aws/keycloak-rds-dev   available

NAME                                                  AGE   STATUS   CAPABILITIES   READY
secretstore.external-secrets.io/aws-secretstore-dev   11m   Valid    ReadWrite      True

NAME                                                       STORETYPE     STORE                 REFRESH INTERVAL   STATUS         READY
externalsecret.external-secrets.io/rds-password-sync-dev   SecretStore   aws-secretstore-dev   1h                 SecretSynced   True

NAME                             TYPE     DATA   AGE
secret/aws-credentials           Opaque   4      2m6s
secret/rds-connection-dev        Opaque   4      7m15s
secret/rds-password-synced-dev   Opaque   2      11m

NAME                           TYPE           CLUSTER-IP      EXTERNAL-IP                                                 PORT(S)    AGE
service/keycloak-service-dev   ClusterIP      10.102.50.198   <none>                                                      8080/TCP   11m
service/kubernetes             ClusterIP      10.96.0.1       <none>                                                      443/TCP    4d3h
service/postgres-service       ExternalName   <none>          keycloak-rds-dev.ckxssqysgxjv.us-east-1.rds.amazonaws.com   5432/TCP   7m15s

NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/keycloak-dev   0/1     1            0           11m

NAME                                READY   STATUS    RESTARTS   AGE
pod/keycloak-dev-6fc5c4bdd9-kgkzf   1/1     Running   0          8m4s
Enter fullscreen mode Exit fullscreen mode

Create a port forward and use keycloakHostname value, in this case "keycloakrds.local".
k8s port forward k9s

For connect con admin, the password is in the secret (rds-password-synced-dev).
Resource graph definition Keycloak api description

CONCLUSION:

The combination of AMDF and KIRO acts as a force multiplier, allowing us to build robust, validated, and reusable OCI packages or in this case Yaml manifests from existing CRDs faster.

Using KCL instead of traditional YAML isn't just a syntax preference—it’s about building a safer, more modular, and maintainable backbone for our Cloud Native ecosystem.

Top comments (0)