6 min read1 day ago
–
Press enter or click to view image in full size
A few months ago, I was knee-deep in CI/CD pipelines, you know, that wonderful mix of YAML, permissions, and secrets that make or break your deployment days. Everything was smooth with GitHub Actions and Azure, until I had to set up Bitbucket Pipelines.
That’s when I realized something shocking: Bitbucket doesn’t support Azure’s OIDC federation. In other words, there was no native way to let Bitbucket securely authenticate to Azure without storing long-lived credentials.
If you’ve ever managed secrets across repositories, you know what that means: endless secret rotations, security risks, and the constant fear that one leaked service principal key could compromise your entire Azure environment.
So I decid…
6 min read1 day ago
–
Press enter or click to view image in full size
A few months ago, I was knee-deep in CI/CD pipelines, you know, that wonderful mix of YAML, permissions, and secrets that make or break your deployment days. Everything was smooth with GitHub Actions and Azure, until I had to set up Bitbucket Pipelines.
That’s when I realized something shocking: Bitbucket doesn’t support Azure’s OIDC federation. In other words, there was no native way to let Bitbucket securely authenticate to Azure without storing long-lived credentials.
If you’ve ever managed secrets across repositories, you know what that means: endless secret rotations, security risks, and the constant fear that one leaked service principal key could compromise your entire Azure environment.
So I decided to build a bridge. Literally.
Introducing BitBridge: Secure Azure Authentication for Bitbucket
BitBridge is a lightweight Azure Function that acts as a secure authentication broker between Bitbucket Pipelines and Azure. Instead of storing credentials in Bitbucket, pipelines request temporary, scoped credentials on demand. These expire automatically within an hour.
It’s like giving Bitbucket just-in-time access to Azure. No secrets, no permanent keys, no sleepless nights.
Here’s how it works at a high level:
- Bitbucket Pipeline sends a signed request to the Azure Function (BitBridge)
- BitBridge verifies the request’s integrity and origin
- It then uses a Management App Registration to generate a temporary secret for the project-specific Azure App
- The pipeline receives the temporary credentials, authenticates to Azure, deploys infrastructure and that’s it.
One hour later, those credentials are useless.
The Pain That Started It All
Before BitBridge, I had a typical setup: multiple Bitbucket repositories, each managing its own Azure deployment. Every repo had a service principal’s credentials stored as environment variables.
Over time, this became a nightmare:
- Credentials expired silently
- Rotations were manual and error-prone
- Auditing usage was nearly impossible
- There was no clean separation between projects
It wasn’t just annoying, it was a security risk waiting to happen.
So I asked myself:
if GitHub Actions can use OIDC to get temporary Azure tokens, why can’t Bitbucket have something similar?
Spoiler: now it can.
The Core Idea: An Authentication Broker
At its core, BitBridge is simple: instead of letting Bitbucket store Azure secrets, it lets Bitbucket ask for them securely.
The architecture revolves around four components:
- **Management App: **A central Azure AD application that has one job: create temporary credentials in project-specific apps. Critically, it can’t deploy resources itself , it just manages credentials. Principle of least privilege in action.
- **Project Apps: **Each project gets its own Azure AD app registration with permissions scoped to exactly what it needs. Project A can’t touch Project B’s resources. Clean separation of concerns.
- BitBridge Function App : This Python-based Azure Function is the heart of the system. It validates requests using cryptographic signatures, checks repository UUIDs against an allowlist, and generates temporary credentials that expire after one hour. (it also deletes the expired secrets)
- **Bitbucket Pipelines: **pipelines now only store one secret: **the function key. **When they need to deploy, they generate a signed request to BitBridge and receive temporary credentials in return. (For better logging and auditing, I was also storing subscription ID, tenant _ID etc. in bitbucket but that is not required for this solution to work)
Each pipeline run triggers a signed request to BitBridge. The Function validates the signature, checks the repository UUID, and issues a short-lived secret to the relevant project app. That secret is used for the deployment, then automatically expires.
Zero credentials stored. Full audit logs. Least privilege. Done.
Building It (and Why It’s So Lightweight)
I built BitBridge as a Python Azure Function, deployable in minutes with zero infrastructure overhead.
Everything runs serverlessly on the Consumption Plan, which means it costs… basically nothing. Even with multiple repositories, most teams won’t ever exceed the free tier.
The function performs a few core tasks:
- Validates request signatures using HMAC-SHA256
- Checks repository UUIDs against allowed values
- Authenticates using the Management App
- Calls Microsoft Graph API to create temporary secrets
- Logs every request and credential creation for audit
The Function App doesn’t store any long-term credentials beyond the Management App’s secret, which can itself be stored in Azure Key Vault.
BitBridge is Open-Source. You can view the code at: https://github.com/ateeb327/BitBridge-Function
The Flow: How It All Works Together
Press enter or click to view image in full size
Let me walk you through what happens when pipeline runs:
- Pipeline Starts: Bitbucket pipeline begins execution
- Signature Generation: The pipeline generates a timestamp and creates an HMAC-SHA256 signature using the function key
- Request to BitBridge: The pipeline calls the Azure Function with the signed request
- Validation: BitBridge verifies the signature and checks the repository UUID
- Credential Creation: BitBridge uses the Management App to create a temporary client secret in project-specific app
- Deployment: The pipeline receives the credentials and uses them to authenticate to Azure
- Auto-Expiration: One hour later, the credentials expire automatically
The beauty? From a security perspective, even if someone intercepts the temporary credentials, they’re useless after 60 minutes. And if they try to request new credentials without proper authorization, BitBridge rejects them.
Get Muhammad Ateeb Aslam’s stories in your inbox
Join Medium for free to get updates from this writer.
Below is the screenshot of Logs:
Press enter or click to view image in full size
The Best Part: Zero Cost, Maximum Security
Let’s be honest: this was meant to be practical, not fancy. I didn’t want a big cloud bill or a complex setup. So I designed BitBridge to be cost-effective:
- Azure Functions (Consumption Plan): Free up to 1M executions/month
- App Registrations: Free
- Application Insights: Free up to 5GB/month
Most users will never pay a cent.
And yet, the security gains are enormous:
- 🔒 No long-lived Azure secrets in Bitbucket
- 🧭 Full audit logging per pipeline run
- 🕒 Temporary credentials that expire automatically
- 🧩 Per-project isolation with least privilege
- ⚙️ Minimal setup: deploy once, use everywhere
The Implementation: Easier Than You Think
I designed BitBridge to be straightforward to set up. Below is the high-level process: (you can find detailed docs on GitHub repo)
Step 1: Create the Management App
Set up an Azure AD app registration with Application.ReadWrite.OwnedBy permissions. This allows it to manage credentials only for apps it owns, no broader access needed.
Step 2: Create Project-Specific Apps
For each project, create a separate app registration with RBAC permissions scoped to the exact resources it needs to deploy. Make the Management App the owner of these apps.
Step 3: Deploy BitBridge
Deploy the Python Azure Function (code available in my repo). Configure environment variables including the Management App credentials and allowed repository UUIDs.
Step 4: Configure Bitbucket
Add the function key and metadata to your Bitbucket repository variables. Update your pipeline YAML to call BitBridge before deploying.
That’s it. The entire setup takes about an hour if you follow the guide.
The Lessons: What I Learned Building This
1. Security Doesn’t Have to Be Complicated The best security solutions are often the simplest. BitBridge uses standard Azure features and proven cryptographic techniques. No magic, no proprietary protocols.
2. Constraints Drive Innovation Bitbucket’s lack of OIDC federation seemed like a limitation. It became an opportunity to build something better tailored to our needs.
3. Separation of Concerns Is Everything By splitting responsibilities between Management App (credential creation) and Project Apps (resource deployment), we created natural security boundaries.
4. Temporary Is Better Than Permanent One-hour credentials force you to think about access differently. If your deployment can’t finish in an hour, maybe it’s time to rethink your deployment strategy.
The Code: Open Source and Ready to Use
BitBridge is completely open source. You can find the complete implementation, including:
- Python Azure Function code with comprehensive error handling
- Step-by-step setup guide
- Troubleshooting documentation
GitHub Repository: github.com/ateeb327/BitBridge-Function
The code is production-ready and includes everything you need to deploy it yourself. I have documented every step, and every troubleshooting scenario I encountered.
Try It Yourself
If you’re struggling with Azure authentication in Bitbucket Pipelines, give BitBridge a shot. The setup takes less than an hour, costs nothing, and immediately improves your security posture.
And if you run into issues or have ideas for improvements, I would love to hear from you. Open an issue on GitHub, send me a message on LinkedIn, or drop me an email.
Because at the end of the day, nobody should have to wake up at 2 AM to a security alert that could have been prevented.
Connect with me:
- GitHub: github.com/ateeb327
- LinkedIn: linkedin.com/in/muhammad-ateeb-aslam
- Email: ateeb327@gmail.com
If this article helped you secure your Bitbucket pipelines, give it a clap and share it with your team. Let’s make credential exposure a thing of the past.