{"id":23086986,"url":"https://github.com/backerman/poudrierec2","last_synced_at":"2026-05-05T00:37:45.583Z","repository":{"id":36958875,"uuid":"365934525","full_name":"backerman/PoudriereC2","owner":"backerman","description":"Azure Functions-based C2 for Poudriere package building. (WIP)","archived":false,"fork":false,"pushed_at":"2024-05-15T08:29:00.000Z","size":5813,"stargazers_count":1,"open_issues_count":22,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-02-09T05:16:56.402Z","etag":null,"topics":["azure","azure-functions","azure-functions-v3","azure-postgres","freebsd","freebsd-ports","fsharp","postgresql","poudriere"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/backerman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2021-05-10T06:02:39.000Z","updated_at":"2023-11-17T06:30:28.000Z","dependencies_parsed_at":"2023-02-19T15:16:00.177Z","dependency_job_id":"e966d6e3-cc8f-4123-8a1d-e092f4dcdadf","html_url":"https://github.com/backerman/PoudriereC2","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/backerman%2FPoudriereC2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/backerman%2FPoudriereC2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/backerman%2FPoudriereC2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/backerman%2FPoudriereC2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/backerman","download_url":"https://codeload.github.com/backerman/PoudriereC2/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247036158,"owners_count":20872908,"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":["azure","azure-functions","azure-functions-v3","azure-postgres","freebsd","freebsd-ports","fsharp","postgresql","poudriere"],"created_at":"2024-12-16T19:40:09.356Z","updated_at":"2026-05-05T00:37:40.563Z","avatar_url":"https://github.com/backerman.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PoudriereC2\n\n\u0026copy; Brad Ackerman. MIT license.\n\nNot an official Microsoft project. This README is not yet complete.\n\n## Setup\n\n### Load database\n\nTo log in with Azure Active Directory, specify the username as the tenant user (without the tenant domain) and set the password to a bearer token:\n\n```powershell\n$Env:PGPASSWORD=(Get-AzAccessToken -ResourceUrl \"https://ossrdbms-aad$((Get-AzContext).Environment.SqlDatabaseDnsSuffix)\").Token\n```\n\nor\n\n```shell\nexport PGPASSWORD=$(az account get-access-token --resource-type oss-rdbms --query \"[accessToken]\" -o tsv)\n```\n\n### Redeploying the function\n\nIf the function is deleted and redeployed, its AAD managed service identity\nwill have a different GUID, and PostgreSQL authentication will fail. To fix\nthis issue, query AAD for the new GUID:\n\n```shell\n# Get the SP ID\naz ad sp list --display-name ffpoudrierec2 --filter \"servicePrincipalType eq 'ManagedIdentity'\" --query '[].id'\n```\n\nThen open `psql` and update the role's security label:\n\n```sql\nsecurity label for \"pgaadauth\" on role ffpoudrierec2 is 'aadauth,oid=\u003cSP-GUID-goes-here\u003e,type=service';\n```\n\nDiscussion: Azure Database for PostgreSQL vs IaaS\n\n```postgresql\nCREATE USER poudrierec2 WITH PASSWORD '«some random and entropic password»';\nGRANT poudriereadmin TO poudrierec2;\n```\n\n### Azure Function\n\nAuthentication. Create new application.\n\nConfiguration -\n\n* PostgresConnection: the connection string for the production database. (FIXME: support Key Vault)\n\nDeployment:\n\n```shell\ndotnet publish --configuration Release /property:GenerateFullPaths=true /consoleloggerparameters:NoSummary \nfunc azure functionapp publish ffpoudrierec2\n```\n\n### Azure Active Directory\n\n#### Create application roles\n\nGo to the AAD application created in the \"Azure Function\" step above. Select the\n\"Create App Role\" button and create three:\n\n| Display name | Value | Allowed member types | Description |\n| --- | --- | --- | --- |\n| Administrator | PoudriereC2.Administrator | Users/Groups | Read and modify all settings. |\n| Viewer | PoudriereC2.Viewer | Users/Groups | Read all non-sensitive settings. |\n| Worker node | PoudriereC2.WorkerNode | Applications | Obtain and report status of build jobs. |\n\n(FIXME: Use app manifest here instead?)\n\nSelect the application in the \"Enterprise applications\" blade. Under \"Users and groups\",\nadd your user to the Administrator role.\n\n#### Grant VM permission to call functions\n\nIt's not yet possible to grant a role to a managed identity from the portal, so\nyou'll need to do it from the command line.\n\n```shell\nappId=$(az ad app list --display-name \"PoudriereC2 API\" --query '[0].appId' --output tsv)\nappSPID=$(az ad sp show --id $appId --query 'objectId' --output tsv)\nworkerNodeRoleID=$(az ad app list --display-name PoudriereC2 --query \"[0].appRoles[?value=='PoudriereC2.WorkerNode'].id | [0]\" --output tsv)\nworkerSPID=$(az identity list --query \"[?name=='poudriereidentity'].principalId | [0]\" --output tsv)\naz rest --method post \\\n    --uri \"https://graph.microsoft.com/v1.0/servicePrincipals/${appSPID}/appRoleAssignedTo\" \\\n    --body \"{ \\\"principalId\\\": \\\"${workerSPID}\\\", \\\"appRoleId\\\": \\\"${workerNodeRoleID}\\\", \\\"resourceId\\\": \\\"${appSPID}\\\" }\"\n```\n\nThe `az rest` command will return an `appRoleAssignment` object and the `poudriereidentity`\nservice principal will now appear in the application's \"Users and Groups\" blade.\n\n#### Get MSI from worker and validate role present\n\n### Security\n\n## Local development\n\nInstall [Azure Functions Core Tools][afct]. Then set `PostgresConnection` with\nthe development database connection string and run `func start` in `backend/Poudrierec2`\nto start the server.\n\nIn a different session, run `yarn dev` to start a webserver hosting the client\nafter configuring the following variables:\n\n| Name | Value |\n| ---- | ----- |\n| NEXT_PUBLIC_AAD_CLIENT_ID | The client ID of the frontend's AAD application |\n| NEXT_PUBLIC_AAD_TENANT_ID | The ID of the tenant containing the frontend application |\n| NEXT_PUBLIC_API_BASE_URL | The URL of the development API server; normally `http://localhost:7071/` |\n| NEXT_PUBLIC_IS_DEVELOPMENT | \"TRUE\" or \"YES\" (case-insensitive) iff a development instance |\n| NEXT_PUBLIC_API_SCOPE | The API scope exposed by the Azure Function |\n\n[afct]: https://learn.microsoft.com/en-us/azure/azure-functions/functions-run-local#install-the-azure-functions-core-tools\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbackerman%2Fpoudrierec2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbackerman%2Fpoudrierec2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbackerman%2Fpoudrierec2/lists"}