Key Vault
Compatible with azure-keyvault-secrets SDKs (Python, Java, JavaScript, .NET).
Features
- Secrets CRUD — set, get, delete, list secrets
- Versioning — each
set_secretcreates a new immutable version; latest pointer tracks the most recent - Soft-delete lifecycle — delete moves a secret to the deleted namespace; recover or purge it
- Properties update — update
content_type,tags,enabled,nbf,expwithout changing the value - Attributes —
enabled,not_before,expires_on; disabled secrets return 403 on get - List operations — list active secrets, deleted secrets, or versions of a specific secret
- Backup — backup a secret (base64-encoded blob)
- 32-char hex version IDs — matches Azure's version ID format
Endpoint
Default account: devstoreaccount1
Default endpoint: http://localhost:4577/devstoreaccount1-keyvault
Connection String
The Key Vault SDK enforces HTTPS and uses a challenge-based auth flow. Use the patterns below to connect to the local emulator:
import re, time
from azure.core.credentials import AccessToken, TokenCredential
from azure.core.pipeline.transport import RequestsTransport
from azure.keyvault.secrets import SecretClient
class FakeCredential(TokenCredential):
def get_token(self, *scopes, **kwargs):
return AccessToken("fake-token", int(time.time()) + 3600)
class ForceHttpTransport(RequestsTransport):
def send(self, request, **kwargs):
request.url = request.url.replace("https://", "http://", 1)
return super().send(request, **kwargs)
account = "devstoreaccount1"
endpoint = "http://localhost:4577"
vault_url = re.sub(r"^http://", "https://", endpoint) + f"/{account}-keyvault"
client = SecretClient(
vault_url=vault_url,
credential=FakeCredential(),
transport=ForceHttpTransport(),
verify_challenge_resource=False,
)
import com.azure.core.credential.AccessToken;
import com.azure.core.credential.TokenCredential;
import com.azure.core.http.HttpPipelineCallContext;
import com.azure.core.http.HttpPipelineNextPolicy;
import com.azure.core.http.HttpResponse;
import com.azure.core.http.policy.HttpPipelinePolicy;
import com.azure.security.keyvault.secrets.SecretClient;
import com.azure.security.keyvault.secrets.SecretClientBuilder;
import reactor.core.publisher.Mono;
import java.net.URL;
import java.time.OffsetDateTime;
static class FakeCredential implements TokenCredential {
@Override
public Mono<AccessToken> getToken(TokenRequestContext req) {
return Mono.just(new AccessToken("fake-token", OffsetDateTime.now().plusHours(1)));
}
}
static class ForceHttpPolicy implements HttpPipelinePolicy {
@Override
public Mono<HttpResponse> process(HttpPipelineCallContext ctx, HttpPipelineNextPolicy next) {
try {
URL url = new URL(ctx.getHttpRequest().getUrl().toString());
ctx.getHttpRequest().setUrl(
new URL("http", url.getHost(), url.getPort(), url.getFile()).toString());
} catch (Exception ignored) {}
return next.process();
}
}
String account = "devstoreaccount1";
String vaultUrl = "https://localhost:4577/" + account + "-keyvault";
SecretClient client = new SecretClientBuilder()
.vaultUrl(vaultUrl)
.credential(new FakeCredential())
.addPolicy(new ForceHttpPolicy())
.disableChallengeResourceVerification()
.buildClient();
Secrets
Set a secret
Get a secret
Delete a secret (soft-delete)
Recover a deleted secret
Purge a deleted secret
Versioning
Every set_secret call creates a new immutable version. The latest version is always returned by get_secret(name).
v1 = client.set_secret("db-password", "hunter2")
v2 = client.set_secret("db-password", "correct-horse-battery-staple")
# Latest is always v2
latest = client.get_secret("db-password")
assert latest.value == "correct-horse-battery-staple"
# Access v1 by version ID
old = client.get_secret("db-password", v1.properties.version)
assert old.value == "hunter2"
# List all versions
for props in client.list_properties_of_secret_versions("db-password"):
print(props.version, props.created_on)
Properties Update
Update metadata without creating a new version:
REST API Reference
All endpoints sit under /{accountName}-keyvault/ with an api-version query parameter.
Secrets
| Method | Path | Description |
|---|---|---|
GET |
/secrets |
List all secrets (properties only, no values) |
GET |
/secrets/{name} |
Get latest version |
PUT |
/secrets/{name} |
Set a secret (creates new version) |
DELETE |
/secrets/{name} |
Soft-delete a secret |
GET |
/secrets/{name}/{version} |
Get a specific version |
PATCH |
/secrets/{name}/{version} |
Update secret properties |
GET |
/secrets/{name}/versions |
List all versions |
POST |
/secrets/{name}/backup |
Backup a secret |
Deleted Secrets
| Method | Path | Description |
|---|---|---|
GET |
/deletedsecrets |
List deleted secrets |
GET |
/deletedsecrets/{name} |
Get a deleted secret |
DELETE |
/deletedsecrets/{name} |
Purge (permanently delete) |
POST |
/deletedsecrets/{name}/recover |
Recover a deleted secret |
Storage Configuration
floci-az:
storage:
services:
key-vault:
# mode: persistent # override global storage mode
flush-interval-ms: 5000
services:
key-vault:
enabled: true
| Environment Variable | Default | Description |
|---|---|---|
FLOCI_AZ_SERVICES_KEY_VAULT_ENABLED |
true |
Enable/disable the service |
FLOCI_AZ_STORAGE_SERVICES_KEY_VAULT_MODE |
(global) | Per-service storage mode |