{"id":51261313,"url":"https://github.com/edneimonteiro/obo-sqlserver","last_synced_at":"2026-06-29T12:02:25.018Z","repository":{"id":367349621,"uuid":"1267534536","full_name":"EdneiMonteiro/obo-sqlserver","owner":"EdneiMonteiro","description":"Azure SQL OBO PoC - ASP.NET Core API on Azure Container Apps using Microsoft Entra ID, Azure SQL Always Encrypted and Azure Key Vault","archived":false,"fork":false,"pushed_at":"2026-06-25T15:07:41.000Z","size":61,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-25T17:06:30.639Z","etag":null,"topics":["always-encrypted","azure","azure-sql","container-apps","dotnet","entra-id","key-vault","obo","poc","security"],"latest_commit_sha":null,"homepage":null,"language":"PowerShell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/EdneiMonteiro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":null,"support":"SUPPORT.md","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-12T16:17:22.000Z","updated_at":"2026-06-25T15:07:45.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/EdneiMonteiro/obo-sqlserver","commit_stats":null,"previous_names":["edneimonteiro/obo-sqlserver"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/EdneiMonteiro/obo-sqlserver","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EdneiMonteiro%2Fobo-sqlserver","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EdneiMonteiro%2Fobo-sqlserver/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EdneiMonteiro%2Fobo-sqlserver/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EdneiMonteiro%2Fobo-sqlserver/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EdneiMonteiro","download_url":"https://codeload.github.com/EdneiMonteiro/obo-sqlserver/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EdneiMonteiro%2Fobo-sqlserver/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34925718,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-29T02:00:05.398Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["always-encrypted","azure","azure-sql","container-apps","dotnet","entra-id","key-vault","obo","poc","security"],"created_at":"2026-06-29T12:02:24.277Z","updated_at":"2026-06-29T12:02:25.013Z","avatar_url":"https://github.com/EdneiMonteiro.png","language":"PowerShell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OBO SQL Server — Azure SQL Always Encrypted PoC\n\n[![ORCID](https://img.shields.io/badge/ORCID-0009--0006--0765--4201-A6CE39?logo=orcid\u0026logoColor=white)](https://orcid.org/0009-0006-0765-4201)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![Azure](https://img.shields.io/badge/Cloud-Azure-0078D4?logo=microsoftazure\u0026logoColor=white)](#)\n[![.NET](https://img.shields.io/badge/.NET-8.0-512BD4?logo=dotnet\u0026logoColor=white)](#)\n[![Security](https://img.shields.io/badge/Security-Always%20Encrypted-2E7D32)](#)\n[![Last commit](https://img.shields.io/github/last-commit/EdneiMonteiro/obo-sqlserver)](https://github.com/EdneiMonteiro/obo-sqlserver/commits)\n\n## Visao Geral\n\nEste repositorio contem uma prova de conceito (PoC) para validar acesso delegado com OAuth2 On-Behalf-Of (OBO) entre uma API em Azure Container Apps, Azure SQL Database e Azure Key Vault.\n\nO objetivo e demonstrar como armazenar documentos sensiveis em Azure SQL usando criptografia de coluna com Always Encrypted, mantendo o material criptografico fora do banco em Azure Key Vault, de forma que um administrador SQL sem permissao no Key Vault nao consiga ler plaintext.\n\nEste projeto foi criado para aprendizado, avaliacao tecnica e experimentacao.\n\n## Aviso Importante\n\nEste repositorio contem **codigo de exemplo e nao e destinado para uso em producao**.\n\nAntes de utilizar qualquer parte deste projeto em um ambiente produtivo ou critico, revise, valide, proteja e adapte o codigo conforme os requisitos da sua organizacao, incluindo:\n\n- Seguranca\n- Escalabilidade\n- Confiabilidade\n- Monitoramento\n- Observabilidade\n- Custos\n- Conformidade\n- Privacidade / LGPD\n\nLeia tambem:\n\n- [DISCLAIMER.md](./DISCLAIMER.md)\n- [SUPPORT.md](./SUPPORT.md)\n\n## O que este exemplo demonstra\n\n- Login de usuario com Microsoft Entra ID\n- Fluxo OAuth2 On-Behalf-Of para Azure SQL\n- Acesso delegado a Azure Key Vault para Always Encrypted\n- Azure SQL com dados sensiveis criptografados em coluna\n- Autorizacao por documento usando `tid` + `oid` do token Entra\n- API .NET 8 Minimal API rodando em Azure Container Apps\n- Infraestrutura como codigo com Bicep\n- Scripts de preflight, deploy, validacao e cleanup\n- Documentacao explicita do limite entre near-E2EE e E2EE estrito\n\n## Near-E2EE vs E2EE estrito\n\nEsta PoC valida um modelo **near-E2EE**:\n\n- O SQL Admin nao deve conseguir ler plaintext.\n- A chave mestra fica no Azure Key Vault.\n- A aplicacao usa a identidade delegada do usuario para acessar SQL e Key Vault.\n- A aplicacao ainda e trusted compute e pode ver plaintext em memoria durante operacoes autorizadas.\n\nSe o requisito for **E2EE estrito**, a criptografia e a descriptografia devem acontecer no cliente final, e o backend deve armazenar apenas ciphertext e metadados.\n\n## Pre-requisitos\n\n- Azure CLI 2.60+ autenticado (`az login --tenant \u003centra-tenant-id\u003e`)\n- GitHub CLI autenticado (`gh auth login`) — opcional\n- .NET 8 SDK\n- Azure CLI Bicep 0.30+ (`az bicep version`)\n- PowerShell 7+\n- Modulo SqlServer 22+ (`Install-Module SqlServer -Scope CurrentUser`)\n- Permissao para criar recursos na subscription alvo\n- Permissao para criar App Registration no Microsoft Entra ID\n- Permissao para conceder admin consent no tenant\n\nTenant alvo: definir antes de rodar o preflight (nao versionar no repositorio).\n\n## Como iniciar\n\n### Editar no VS Code\n\nSim. O repositorio inclui configuracao em `.vscode/` com extensoes recomendadas, tarefas de restore/build/test/run e launch para debug da API.\n\n```powershell\ncode .\n```\n\nNo VS Code:\n\n1. Instale as extensoes recomendadas quando solicitado.\n2. Use `Terminal \u003e Run Task` para `dotnet: restore`, `dotnet: build`, `dotnet: test` ou `api: run`.\n3. Use `Run and Debug \u003e API: debug` para depurar a API.\n\n### Provisionar e validar (resumo)\n\nO guia completo passo a passo esta em [docs/deploy.md](docs/deploy.md). Resumo dos comandos:\n\n```powershell\n# 1. Preflight\n.\\scripts\\preflight-azure.ps1 -TenantId \"\u003centra-tenant-id\u003e\" -ForecastsPath \".\\forecasts.local.json\"\n\n# 2. Deploy infra\nCopy-Item .\\infra\\bicep\\main.parameters.json.example .\\infra\\bicep\\main.parameters.local.json\n.\\scripts\\deploy-infra.ps1 -SubscriptionId \"\u003csub-id\u003e\" -ResourceGroupName \"rg-obo-sql-poc-brs-001\" `\n  -ParametersFile \".\\infra\\bicep\\main.parameters.local.json\"\n\n# 3. Liberar IP do operador no SQL (one-off)\n$myIp = (Invoke-RestMethod 'https://api.ipify.org?format=json').ip\naz sql server firewall-rule create -g rg-obo-sql-poc-brs-001 -s \u003csql-server\u003e `\n  -n allow-operator-ip --start-ip-address $myIp --end-ip-address $myIp\n\n# 4. Always Encrypted (CMK + CEK + tabelas)\n.\\scripts\\setup-always-encrypted.ps1 -SqlServerFqdn \"\u003csql\u003e.database.windows.net\" `\n  -DatabaseName \"sqldb-obo-sql-poc\" -KeyVaultKeyUrl \"\u003ckeyVaultKeyId\u003e\"\n\n# 5. App Registration (scope, perms, secret)\n.\\scripts\\create-app-registration.ps1 -TenantId \"\u003ctenant\u003e\" `\n  -SecretOutputPath \".\\client-secret.local.txt\"\n\n# 6. Build e push da imagem\n.\\scripts\\build-and-push-image.ps1 -SubscriptionId \"\u003csub-id\u003e\" `\n  -ResourceGroupName \"rg-obo-sql-poc-brs-001\" -AcrName \"cr\u003crandom\u003e\" -Tag \"1.0.0\"\n\n# 7. Atualizar Container App\n.\\scripts\\update-container-app.ps1 -SubscriptionId \"\u003csub-id\u003e\" `\n  -ResourceGroupName \"rg-obo-sql-poc-brs-001\" `\n  -ContainerAppName \"ca-obo-sql-api-poc-brs\" `\n  -ManagedIdentityName \"id-obo-sql-api-poc-brs\" `\n  -AcrName \"cr\u003crandom\u003e\" `\n  -Image \"\u003cacr\u003e.azurecr.io/obo-sqlserver-api:1.0.0\" `\n  -TenantId \"\u003ctenant\u003e\" -ApiClientId \"\u003cclient-id\u003e\" `\n  -ClientSecretFile \".\\client-secret.local.txt\"\n\n# 8. Validacao end-to-end (7 testes)\n.\\scripts\\validate-poc.ps1 -BaseUrl \"https://\u003capp-url\u003e\" `\n  -ApiClientId \"\u003cclient-id\u003e\" `\n  -SqlServerFqdn \"\u003csql\u003e.database.windows.net\" -DatabaseName \"sqldb-obo-sql-poc\"\n\n# 9. Cleanup\n.\\scripts\\cleanup.ps1 -SubscriptionId \"\u003csub-id\u003e\" -ResourceGroupName \"rg-obo-sql-poc-brs-001\"\n```\n\n## Arquitetura\n\n```mermaid\nsequenceDiagram\n    participant Sender as Sender Client\n    participant App as Container App API\n    participant Entra as Microsoft Entra ID\n    participant KV as Azure Key Vault\n    participant SQL as Azure SQL Database\n    participant Receiver as Receiver Client\n\n    Sender-\u003e\u003eEntra: Login OAuth2\n    Sender-\u003e\u003eApp: POST /documents com bearer token\n    App-\u003e\u003eEntra: OBO token para SQL/KV\n    App-\u003e\u003eKV: unwrap/acesso CMK via Always Encrypted\n    App-\u003e\u003eSQL: INSERT ciphertext + ACL\n    Receiver-\u003e\u003eEntra: Login OAuth2\n    Receiver-\u003e\u003eApp: GET /documents/{id}\n    App-\u003e\u003eSQL: Verifica ACL por tid/oid\n    App-\u003e\u003eKV: unwrap/acesso CMK via Always Encrypted\n    App--\u003e\u003eReceiver: Plaintext somente se autorizado\n```\n\n| Recurso | Finalidade |\n|---------|------------|\n| Azure Container Apps | Hospeda a API .NET 8 |\n| Azure SQL Database | Armazena documentos criptografados e metadados de ACL |\n| Azure Key Vault | Armazena a Column Master Key usada pelo Always Encrypted |\n| Microsoft Entra ID | Autenticacao, tokens e fluxo OBO |\n| Log Analytics | Logs operacionais sem payload sensivel |\n\n## Documentacao\n\n| Documento | Descricao |\n|-----------|-----------|\n| [docs/deploy.md](docs/deploy.md) | Guia end-to-end de deploy, configuracao, validacao e troubleshooting |\n| [docs/separation-of-duties.md](docs/separation-of-duties.md) | Prova reproduzivel de que AE+AKV bloqueia o SQL admin sem KV access |\n| [docs/arquitetura.md](docs/arquitetura.md) | Arquitetura e principais decisoes |\n| [docs/classes-e-metodos.md](docs/classes-e-metodos.md) | Diagrama de classes e referencia das classes/metodos da API |\n| [docs/fluxo-logico.md](docs/fluxo-logico.md) | Fluxo detalhado de escrita e leitura |\n| [docs/componentes-azure.md](docs/componentes-azure.md) | Componentes Azure e escolhas de SKU |\n| [docs/modelo-ameacas.md](docs/modelo-ameacas.md) | Ameacas cobertas, nao cobertas e riscos residuais |\n| [docs/validacao.md](docs/validacao.md) | Criterios de validacao e resultados |\n| [docs/publicacao.md](docs/publicacao.md) | Checklist antes de tornar o repositorio publico |\n\n## Suporte\n\nEste projeto **nao possui SLA nem suporte oficial**.\n\nVeja [SUPPORT.md](./SUPPORT.md) para detalhes.\n\n## Aviso Legal\n\nO uso deste projeto esta sujeito aos termos descritos em [DISCLAIMER.md](./DISCLAIMER.md).\n\n## Contribuicoes\n\nContribuicoes podem ser aceitas a criterio do mantenedor.\n\n## Marcas Registradas (Trademarks)\n\nOs nomes e servicos da Microsoft sao utilizados apenas para fins descritivos.\n\nEste projeto **nao e afiliado, endossado ou suportado oficialmente pela Microsoft**.\n\nO uso de marcas da Microsoft nao deve sugerir qualquer tipo de parceria ou suporte oficial.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fedneimonteiro%2Fobo-sqlserver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fedneimonteiro%2Fobo-sqlserver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fedneimonteiro%2Fobo-sqlserver/lists"}