Skip to content
Notifications
Clear all

We built a CLI tool to bridge a Delinea gap - sharing the code

25 Posts
25 Users
0 Reactions
1 Views
(@gracec)
Reputable Member
Joined: 3 months ago
Posts: 314
Topic starter   [#29024]

Hello everyone,

I've been living in the world of privileged access management and SaaS integrations for a while now, and like many of you, I've hit a specific workflow snag with Delinea (formerly Thycotic). Our security team loves the core Secret Server vault, but our development and operations teams needed a more streamlined, script-friendly way to *use* those secrets in automated local environments and CI/CD pipelines, without always going through the web UI or full SDKs for simple tasks. The existing tools were powerful but sometimes felt like using a sledgehammer to crack a nut for our day-to-day, local development needs.

So, a couple of us on the platform engineering team decided to bridge that gap ourselves. We built a lean CLI tool, internally called `vaultbridge`, to serve as a simple, secure bridge between Delinea and our local terminals and scripts. The core idea was to combine the robust security of the central vault with the immediate, practical utility of a command-line interface for developers. We've been using it internally for about six months, and it's significantly reduced friction and those "just-in-case" local .env files we all know are a bad idea.

I wanted to share the approach and our core code logic here, as I think it might solve a similar pain point for some of you. Our tool focuses on a few key commands:

* **`fetch`**: Retrieve a specific secret by its path/ID and inject it directly into a command or local environment variable.
* **`preflight`**: Validate local configuration and connectivity to the Delinea instance before running sensitive scripts.
* **`list`**: A safe, limited view of accessible secret folders (not the secrets themselves) to aid in discovery.

The heart of it is a simple configuration layer that uses our existing SSO and the Delinea REST API. We made a conscious decision to *not* store any credential material locally, instead relying on short-lived tokens fetched via our existing identity provider. The configuration is just a small JSON file that points to our Delinea instance and the OAuth2 endpoints.

Here's a snippet of the core configuration structure we used:

```
{
"delinea_base_url": "https://vault.yourcompany.com",
"token_endpoint": "https://auth.yourcompany.com/oauth/token",
"client_id": "your-cli-client-id",
"scope": "secret-server:*"
}
```

And a typical use case in a developer's shell script would look like this, replacing what used to be a manual login and copy-paste from the web UI:

```
#!/bin/bash
# Old way: API_KEY=$(cat ~/unsafe_local_file.txt)
# New way:
export API_KEY=$(vaultbridge fetch --id 42 --field apiKey)
./deploy_script.sh
```

We're open-sourcing the core code on our company's GitHub (link in my profile, as per community rules on self-promotion). It's not an official product, just a well-tested internal tool we're happy to share. I'm particularly interested in hearing how others have solved this problem, or if you see any pitfalls in our approach from a security or workflow perspective. Have any of you built similar connectors? What were your key requirements?

grace


The right tool saves a thousand meetings.


   
Quote
(@elenag)
Reputable Member
Joined: 2 months ago
Posts: 334
 

Oh, this is such a timely topic for me. We've had the same exact conversation on our martech team about secure API keys and database credentials for our local testing environments. That friction point you mentioned, between the secure central vault and the practical need for script-friendly access, is so real.

I'm really curious about how you handled authentication and session management in your CLI. Did you bake in any kind of short-lived token refresh, or is it more of a per-command auth flow? Also, for secrets that have dynamic fields or require approval workflows, does your tool handle that gracefully or does it just error out?

Really looking forward to seeing the code. Sharing something like this is such a great help to the community.


test everything twice


   
ReplyQuote
(@integration_ian_2)
Honorable Member
Joined: 4 months ago
Posts: 514
 

>the practical need for script-friendly access

You've nailed the core tension. We've tried solving this a few different ways over the years, and the big challenge we always hit was making it simple enough for devs to actually adopt while keeping the security team happy. For our own scripts, we leaned on environment variables populated via a short-lived token that refreshes under the hood, which kept credential rotation out of the developer's immediate workflow.

For dynamic fields or approval workflows, our initial version just errored with a clear message pointing to the UI. We found that was better than trying to replicate complex flows in the CLI and creating a maintenance nightmare. Curious if your team took a different path there.


api first


   
ReplyQuote
(@annar)
Estimable Member
Joined: 2 months ago
Posts: 208
 

You're absolutely right about the maintenance nightmare of trying to replicate complex UI workflows. Our approach is almost identical to the one you described. We treat the CLI as a fast, read-only conduit for secrets that are already in a "ready" state, and anything requiring approval, dynamic fields, or a checkout workflow simply returns a clear error with a direct link to the Secret Server UI item and the required action.

Where we diverged slightly was on the authentication refresh strategy. We implemented a dual-layer token cache: a memory cache for the active shell session (lasting a few hours) and a secure, encrypted file cache for longer-lived background jobs. This meant a developer running ad-hoc commands gets seamless refreshes, but a CI/CD pipeline runner has a deterministic, slightly longer-lived token written to a locked-down environment variable, avoiding mid-build failures. It was a minor compromise that placated both our security auditors, who wanted strict TTLs, and our platform team, who needed reliability in automated flows.

I'm curious, did you encounter any pushback from developers on the "error and link to UI" pattern for complex secrets, or was the clarity of the error message enough to satisfy them?


RTFM — then ask for the audit


   
ReplyQuote
(@annas)
Honorable Member
Joined: 2 months ago
Posts: 542
 

The dual-layer cache strategy you mentioned is the kind of practical compromise I can get behind. We tried something similar but ran into a specific edge case your team might not have hit yet: what happens when a background job's file-cached token expires mid-execution of a *long-running* process, like a data migration or batch job? Our initial implementation just failed hard, which was unacceptable.

We solved it by having the CLI client in those jobs periodically attempt a silent refresh using the file-based refresh token before any secret fetch operation. If that fails, it emits a structured error log and exits cleanly, allowing the orchestrator (like a workflow engine) to handle retry logic with fresh auth. It added a bit of complexity but made the system far more resilient for hours-long processes.

On the error and link pattern, we got initial pushback from exactly one team who had a secret with a mandatory 4-hour checkout they constantly forgot about. The noise from their failures actually forced a conversation with security, and we ended up creating a separate, simplified template for those CI-only secrets that bypassed the checkout requirement. The CLI's strict behavior indirectly improved the underlying secret design.



   
ReplyQuote
(@carolp)
Reputable Member
Joined: 2 months ago
Posts: 363
 

We got zero pushback on the error-and-link approach. Devs liked the clarity. The link is a deep link with the secret ID and a query param like `?action=checkout`, so they go straight to the button they need.

Our bigger fight was about *which* secrets should be blocked. We defaulted to blocking anything with a dependency, a template, or an active workflow. Some teams argued their "dependent" secrets were always safe. We had to make that configurable with a strict allowlist.

Your encrypted file cache is smart. We used a similar pattern but stored it in the OS keychain on Mac/Linux (`libsecret`) and the Windows credential manager. It removed the need to manage file permissions.


—cp


   
ReplyQuote
(@charlie99)
Reputable Member
Joined: 2 months ago
Posts: 310
 

Oh, using the OS keychain is a fantastic idea. It completely sidesteps the file permission headaches we had to document for our encrypted cache file. That's a cleaner abstraction for sure.

>The link is a deep link with the secret ID

We do the same! We also append the CLI command that triggered the error as a URL fragment, so when a dev completes the workflow in the UI, they can see exactly what they were trying to run. It's a tiny touch that's cut down on support questions.

On the allowlist point, we hit that exact debate. We ended up with a similar configurable blocklist, but we also added metadata tags in Delinea that the CLI can read. So a secret could be tagged `cli:unsafe` and be blocked, even if it *technically* passes the other checks. Gives the security team a finer-grained kill switch without touching the config file.


Data nerd out


   
ReplyQuote
(@cassie2)
Honorable Member
Joined: 2 months ago
Posts: 546
 

>periodically attempt a silent refresh... before any secret fetch operation

That's a really smart pattern. We handled long-running jobs differently, by having the CLI output the raw secret to stdout and then exit immediately, letting the calling process (like a bash script) store it in a variable. The token only needs to be valid for that single moment of fetch. It pushes the responsibility for secret longevity onto the job's environment, but it simplified our client logic a ton.

I love that your team's friction point with the 4-hour checkout actually led to a better secret template. Sometimes the CLI isn't the solution - it's the catalyst that exposes the process problem.



   
ReplyQuote
(@grafana_knight_shift_2)
Honorable Member
Joined: 4 months ago
Posts: 472
 

That stdout pattern is clean, I like it. It forces the secret lifecycle management back into the application layer, which is where it probably should be anyway.

The only caveat we ran into was when the secret fetch itself could take a long time due to network or Delinea API lag, causing the token to expire mid-call. We added a pre-fetch token validity check with a configurable buffer, like 5 minutes, to fail fast before even attempting the API request. It added a tiny bit of overhead but saved us from some gnarly partial-failure states in pipelines.

Your point about the CLI exposing process problems is spot on. We had a similar revelation with a "secret not found" error that kept popping up, which turned out to be a permissions sync delay issue on the backend. The CLI didn't fix it, but it made the symptom so frequent and visible that the infra team finally prioritized the root cause.


Sleep is for the weak


   
ReplyQuote
(@cloud_ops_learner_2)
Honorable Member
Joined: 4 months ago
Posts: 560
 

That initial friction point with the .env files is exactly why we built our own wrapper. It's amazing how a simple CLI can change behavior. We saw those risky local credential files almost disappear overnight because the CLI was just easier.

One thing we learned, though, is that you have to pair it with really clear guardrails. We had a dev pipe the secret fetch directly into a `docker run -e` command, which was great, but then the secret sat in their shell history. We added a quick flag `--no-echo` and a note in the help text to use `$(vaultbridge get ...)` for that exact reason.

Great idea sharing the code. Can't wait to see how you handled the auth flow.


Infrastructure as code is the only way


   
ReplyQuote
(@cloud_security_sera)
Honorable Member
Joined: 3 months ago
Posts: 533
 

Good. Reducing local .env files is a solid win.

But be careful with the "script-friendly" promise. If you make fetching a secret too trivial, you risk baking them into scripts and Docker layers just as easily. Did you add any runtime checks to prevent that, like scanning for secrets in build logs or container images?


Least privilege is not a suggestion.


   
ReplyQuote
(@crusty_pipeline_redux)
Honorable Member
Joined: 6 months ago
Posts: 468
 

>significantly reduced friction and those "just-in-case" local .env files

Good. Now you've just moved the problem. Your script is the new .env file.

If fetching a secret is a one-liner, what's stopping a dev from pasting that line into a Dockerfile or a checked-in Jenkins script? Your "secure bridge" just becomes the new insecure conduit unless you bake in runtime checks. Did you?


-- old school


   
ReplyQuote
 dant
(@dant)
Honorable Member
Joined: 2 months ago
Posts: 434
 

That's a valid critique. Our runtime check is a separate auditing service that scans CI/CD logs, Dockerfile layers, and git history using pattern matching for our CLI's token structure and the Delinea API's response envelope. The CLI itself can't prevent embedding.

However, the bigger mitigation is that the one-liner still requires a valid, non-expired OAuth token in the user's session or keychain to execute. Embedding `vaultbridge get secret-x` in a Dockerfile will fail during the build unless the entire token cache is also embedded, which is a more obvious and fragile anti-pattern. It shifts the risk from a static secret in plaintext to a dynamic, scoped credential that's harder to leak accidentally.



   
ReplyQuote
(@benchmark_bob_42)
Honorable Member
Joined: 5 months ago
Posts: 432
 

The pre-fetch token validity check is a pragmatic guard. We implemented something similar after observing latency spikes in Delinea's API during peak hours that could stretch a simple fetch to 30+ seconds. Our buffer is 2 minutes, but we made it dynamically adjustable based on a rolling percentile of recent fetch durations.

>it made the symptom so frequent and visible that the infra team finally prioritized the root cause.

This is the hidden value of a good CLI. It turns intermittent backend issues into consistent, user-facing errors, which creates the operational pressure needed for a fix. We saw the same with permission propagation delays; our CLI's retry logic with exponential backoff generated a very distinct error pattern in logs that finally got the platform team to investigate the caching layer.


-- bb42


   
ReplyQuote
(@davidw)
Reputable Member
Joined: 2 months ago
Posts: 319
 

You've reduced the friction, sure. But what's your metric for success? "Significantly reduced friction" usually just means you've hidden the true cost by moving it to the authentication and token management layer.

If you haven't measured the increase in API calls to Delinea or tracked the support load for OAuth token issues, you're just trading one operational headache for another.


Trust but verify.


   
ReplyQuote
Page 1 / 2