{"id":15430501,"url":"https://github.com/lenisha/spring-cosmosdb-msi","last_synced_at":"2025-11-09T07:30:34.258Z","repository":{"id":116070921,"uuid":"248792251","full_name":"lenisha/spring-cosmosdb-msi","owner":"lenisha","description":"Demo AKS Java app with CosmosDB and AAD Pod Identity and Vault","archived":false,"fork":false,"pushed_at":"2020-03-20T22:17:09.000Z","size":133,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-10-18T06:16:03.205Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lenisha.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-03-20T15:41:17.000Z","updated_at":"2020-04-19T18:54:13.000Z","dependencies_parsed_at":null,"dependency_job_id":"e5c9e152-21cd-4d8b-a924-08a3ea5cd72a","html_url":"https://github.com/lenisha/spring-cosmosdb-msi","commit_stats":{"total_commits":4,"total_committers":1,"mean_commits":4.0,"dds":0.0,"last_synced_commit":"f5dba1dc6912852c1dd77cc4911a0ccbcd63ea6e"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lenisha%2Fspring-cosmosdb-msi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lenisha%2Fspring-cosmosdb-msi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lenisha%2Fspring-cosmosdb-msi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lenisha%2Fspring-cosmosdb-msi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lenisha","download_url":"https://codeload.github.com/lenisha/spring-cosmosdb-msi/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239571542,"owners_count":19661164,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-01T18:16:44.861Z","updated_at":"2025-11-09T07:30:34.213Z","avatar_url":"https://github.com/lenisha.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SpringBoot Demo on how to use CosmosDB with Azure AKS AAD Pod Identities\n\nThis application will use AKS [AAD Pod Identity](https://github.com/Azure/aad-pod-identity)to Connect to Vault and retrieve Mongo connection string for CosmosDb instance.\nIt uses [Azure SpringBoot KeyVault Starter](https://github.com/microsoft/azure-spring-boot/tree/master/azure-spring-boot-starters/azure-keyvault-secrets-spring-boot-starter) to automate communications to Vault and present values of secrets as SpringBoot configuration properties.\n\n![docs](./docs/AAD-Cosmos.png)\n\n\n## Build Docker and Push to ACR \n\nBuild code using Maven, build docker image and push to ACR using ACR Tasks \nDocker image uses laeers for optimization\n\n```\nmvn clean package -DskipTests\naz.cmd acr build --registry \u003cregistryname\u003e -g \u003cresourcegroup\u003e --image cosmosmsi:latest . \n```\n\n## Create AAD IDdentity and setup it's permissions\nTo assign MSI to application running in K8S use [AAD Pod Identity](https://github.com/Azure/aad-pod-identity) project.\n\n1. Install AAD Pod identity\n\n```\nkubectl apply -f https://raw.githubusercontent.com/Azure/aad-pod-identity/master/deploy/infra/deployment-rbac.yaml\n```\n2. Create Managed Identity and record the output Json\n```\n az identity create -g \u003cresourcegroup\u003e -n \u003cidentityname\u003e -o json\n{\n  \"clientId\": \"xxxxx-2bb7-4d06-ba43-cff38b07a026\",\n  \"clientSecretUrl\": \"https://control-canadacentral.identity.azure.net/subscriptions/xxx\",\n  \"id\": \"/subscriptions/xxx/resourcegroups/aks-tests/providers/Microsoft.ManagedIdentity/userAssignedIdentities/odbcidentity\",\n  \"location\": \"canadacentral\",\n  \"name\": \"mongoidentity\",\n  \"principalId\": \"xxx\",\n  \"resourceGroup\": \"xxx\",\n  \"tags\": {},\n  \"tenantId\": \"xxx\",\n  \"type\": \"Microsoft.ManagedIdentity/userAssignedIdentities\"\n}\n```\n\n3. find what service Principal is used by AKS (or MSI if used in provisioing) and grand it access to manage Pod Managed Identity\n\n```\naz aks show -g \u003cresourcegroup\u003e -n \u003caksname\u003e  | grep clientId\n```\n\n- grant AKS client principal access to MSI identity we created\n\n```\naz role assignment create --role \"Managed Identity Operator\" --assignee \u003caks clientid\u003e --scope /subscriptions/\u003ctenantId\u003e/resourcegroups/\u003crg\u003e/providers/Microsoft.ManagedIdentity/userAssignedIdentities/\u003cMI name\u003e\n```\n\n4. Add access policy to KeyVault using Identity ClientID\n\n```\naz keyvault set-policy --name \u003ckv name\u003e -g \u003cresource group\u003e --secret-permission set get list  --spn \"xxxxx\"\n\n```\n## Map AAD Identity to App Pod \n\n5. Create Azure Pod Identity and Binding in K8S for the pods to use\n```\n kubectl apply -f manifests/aadpodidentity.yaml\n```\n- Pod identity Manifests describing identity to bind to applications\n\n```yaml\napiVersion: \"aadpodidentity.k8s.io/v1\"\nkind: AzureIdentity\nmetadata:\n  name: aksmongopodidentity\nspec:\n  type: 0\n  ResourceID: /subscriptions/\u003ctenant\u003e/resourcegroups/\u003crg\u003e/providers/Microsoft.ManagedIdentity/userAssignedIdentities/\u003cidentityname\u003e\n  ClientID: \u003cidentity clientId\u003e\n--- \napiVersion: \"aadpodidentity.k8s.io/v1\"\nkind: AzureIdentityBinding\nmetadata:\n  name: aksmongopodidentity-binding\nspec:\n  AzureIdentity: \"aksmongopodidentity\"\n  Selector: \"mongoidentity\"\n```\n\nNow any Pod having label `aadpodidbinding: mongoidentity` will be bind to created MSI and will use it for MSI enabled calls\n\n6. Update Kubernetes Manifest to add AAD Pod label and enable MSI for connection string, as example in  updated to have `aadpodidbinding` label:\n\n```yaml\ntemplate:\n    metadata:\n      labels:\n        app: cosmosmsi\n        aadpodidbinding: mongoidentity\n```\n7. Create a secret that will hold details to connect to Keyvault\n\n```sh\nkubectl create secret generic vault-connect  --from-literal=azure.keyvault.uri=https://\u003cvaultname\u003e.vault.azure.net/ \\\n                                            --from-literal=azure.keyvault.client-id=\u003cMSI Identity ClientID\u003e\n```\n\n8. Update Environment variable for Pods to read ClientID of MSI that is used  to connect to Vault, in `manifests/k8-manifest.yaml`:\n\n```yaml\n    image: acraccess.azurecr.io/cosmosmsi:latest\n    imagePullPolicy: Always\n    envFrom:\n      - secretRef:\n         name: vault-connect \n```\n\n9. Add MongoDB connection to KeyVault\nGet Mongodb Connection string and add to KeyVault Secret\n\n```\nsecret name = spring-data-mongodb-uri\nsecret value = mongodb://xxxx@.mongo.cosmos.azure.com:10255/?ssl=true\u0026replicaSet=globaldb\u0026maxIdleTimeMS=120000\u0026retrywrites=false'\n```\n\n10. Code Details\n\n- add to `pom.xml` azure springboot keyvault starter\n\n```xml\n\t\u003cdependency\u003e\n\t\t\t\u003cgroupId\u003ecom.microsoft.azure\u003c/groupId\u003e\n\t\t\t\u003cartifactId\u003eazure-keyvault-secrets-spring-boot-starter\u003c/artifactId\u003e\n\t\u003c/dependency\u003e\n```\n\n- Add `MongoConfig` Class extending  `AbstractMongoClientConfiguration`, it  creates `MongoClient` based on value of connection string read from Vault\n\n```java\n    @Value(\"${spring-data-mongodb-uri}\")\n    private String vaultMongoUri;\n    \n    @Value(\"${spring.data.mongodb.database}\")\n    private String mongoDBName;\n\n    @Override\n    public MongoClient mongoClient() {\n\t\treturn MongoClients.create(vaultMongoUri);\n    }\n```\n\n11. Deploy application on K8S and expose as service to reach for testing\n\n```\nkubectl apply -f manifests/k8sdeployment.yaml\nkubectl apply -f manifests/k8ssvc.yaml\n```\n\nGo to see in action: http://\u003cservice ip\u003e/customer\n\nNote: Populate mongodb first using Runner in this app (or find the POSTs)\n\n## Verify logs\n\nCheck logs of nmi Daemonset pods to see how token is obtained\n```sh\nkubectl logs nmi-glh6l\n\ntime=\"2020-03-20T21:28:39Z\" level=info msg=\"matched identityType:0 clientid:15c2##### REDACTED #####3cbc resource:https://vault.azure.net\" req.method=GET req.path=/metadata/identity/oauth2/token req.remote=10.240.0.38\ntime=\"2020-03-20T21:28:39Z\" level=info msg=\"Status (200) took 7494607 ns\" req.method=GET req.path=/metadata/identity/oauth2/token req.remote=10.240.0.38\n```\n\n## Test tokens on the pods\nAt NMI pod\n```\nwget  --header \"podname: cloudquery-web-6575cb496f-4ghsn\" --header \"podns: default\" -S  -O log    http://127.0.0.1:2579/host/token/?resource=https%3A%2F%2Fvault.azure.net%0A\n```\n\nAt app pod:\n\n```\n curl http://169.254.169.254/metadata/identity/oauth2/token?resource=https://vault.azure.net\n\n wget http://169.254.169.254/metadata/identity/oauth2/token?resource=https%3A%2F%2Fvault.azure.net%0A  -S  -O log\n```\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flenisha%2Fspring-cosmosdb-msi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flenisha%2Fspring-cosmosdb-msi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flenisha%2Fspring-cosmosdb-msi/lists"}