承接 smithingdev/laravel-vault 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

smithingdev/laravel-vault

Composer 安装命令:

composer require smithingdev/laravel-vault

包简介

A small, focused Laravel client for HashiCorp Vault: AppRole/token auth and KV2 secret CRUD.

README 文档

README

A small, focused Laravel client for HashiCorp Vault: AppRole/token authentication and KV2 secret CRUD. No domain assumptions — just the transport.

Requirements

  • PHP 8.2+
  • Laravel 11, 12, or 13 (illuminate/http + illuminate/support)

Install

composer require smithingdev/laravel-vault
php artisan vendor:publish --tag=vault-config

The service provider and Vault facade are auto-discovered.

Configure

Set these in .env:

VAULT_ADDR=https://vault.example.com
VAULT_AUTH_METHOD=approle          # approle | token

# AppRole
VAULT_ROLE_ID=...
VAULT_SECRET_ID=...

# or a pre-issued token
VAULT_TOKEN=hvs....

# Namespaces (see "Namespace modes" below)
VAULT_NAMESPACE_MODE=header        # header (default) | path
VAULT_NAMESPACE=acme/dev           # Enterprise namespace (optional)
VAULT_KV_MOUNT=secret              # KV2 mount point (header mode)

VAULT_VERIFY=true                  # TLS verification (see below)
VAULT_TIMEOUT=10                   # per-request timeout in seconds (default 10)
VAULT_LOG_CHANNEL=                 # optional log channel (see below)

TLS verification

VAULT_VERIFY controls how the Vault server's certificate is checked:

  • true (default) — verify against the system CA bundle. Keep this in production.
  • false — disable verification. Only for local/self-signed setups you trust.
  • a filesystem path — verify against a custom CA bundle (e.g. a private CA).

Logging

VAULT_LOG_CHANNEL is optional and disabled by default. When set to a configured log channel, the package logs a line on successful authentication and logs the raw Vault response body (at error level) whenever a request fails — the body is logged rather than thrown, so it never leaks into exception messages (see Errors).

Namespace modes

Vault supports two equivalent ways to address an Enterprise namespace, and this package lets you pick via VAULT_NAMESPACE_MODE:

  • header (default, conventional) — the model the Vault CLI and official clients use. VAULT_NAMESPACE is sent as the X-Vault-Namespace header on every request, and VAULT_KV_MOUNT is the KV2 mount point. Requests go to /v1/<mount>/data/<path>. If you don't use Enterprise namespaces, leave VAULT_NAMESPACE empty and set VAULT_KV_MOUNT to your mount (default secret).

  • path (legacy)VAULT_KV_NAMESPACE is the full path where the KV2 engine is mounted and is embedded directly in every KV2 URI (/v1/<kv_namespace>/data/<path>); the namespace header is sent on login only.

    VAULT_NAMESPACE_MODE=path
    VAULT_NAMESPACE=acme/dev                # X-Vault-Namespace on login
    VAULT_KV_NAMESPACE=acme/dev/kv-secrets  # baked into every KV2 URI

Upgrading from a version without VAULT_NAMESPACE_MODE: the default is now header. If you previously relied on VAULT_KV_NAMESPACE, set VAULT_NAMESPACE_MODE=path (and keep VAULT_KV_NAMESPACE) to retain the old behavior.

Usage

Use the facade, or inject VaultService anywhere the container resolves dependencies:

use Smithingdev\Vault\Facades\Vault;

Vault::read('myapp/database');
use Smithingdev\Vault\VaultService;

class RotateSecrets
{
    public function __construct(private VaultService $vault) {}

    public function handle(): void
    {
        $this->vault->read('myapp/database');
    }
}

KV2 operations

Vault::write('myapp/database', ['username' => 'app', 'password' => '...']);

$secrets = Vault::read('myapp/database');              // array|null
$old     = Vault::read('myapp/database', version: 2);

$keys = Vault::list('myapp');                          // array<string>

Vault::delete('myapp/database');                 // soft-delete latest version (recoverable)
Vault::destroy('myapp/database');                // permanent: all versions + metadata

Return values and not-found behavior:

Method Returns When the path is missing (404)
read($path, $version = null) array<string, mixed>|null null (also null if a 200 response carries no data.data)
write($path, array $data) void — (creates the path)
list($path) array<int, string> (keys directly under the path) []
delete($path) void no-op
destroy($path) void no-op

delete() soft-deletes the latest version — KV2 keeps it recoverable via Vault's undelete endpoint until it's destroyed. destroy() permanently removes all versions and metadata and cannot be undone. Any other failure throws (see Errors).

Authentication

authenticate() runs automatically on the first call and the token is cached for the process lifetime. With AppRole the client re-authenticates once on a 401/403 and retries the failed request, so an expired token is transparently refreshed. The token auth method uses a pre-issued token and cannot self-refresh.

Errors

Every failure surfaces as a single exception type, Smithingdev\Vault\Exceptions\VaultException (a RuntimeException), so you only have to catch one thing:

use Smithingdev\Vault\Exceptions\VaultException;

try {
    $secrets = Vault::read('myapp/database');
} catch (VaultException $e) {
    // log, alert, fall back, ...
}

A VaultException is thrown when:

  • Vault returns a failing HTTP status other than the not-found cases handled above (read/list/delete/destroy treat 404 as "missing", not an error).
  • A transport-level problem occurs (timeout, DNS, connection refused) — these are wrapped so you never have to catch Guzzle's ConnectionException separately.
  • Authentication is misconfigured (no token for token auth, missing AppRole credentials) or login fails.
  • namespace_mode is set to anything other than header or path.

Exception messages are intentionally generic (e.g. Vault read 'foo' failed (HTTP 500).). The raw Vault response body is not included in the message — it is sent to the configured log channel instead (see Logging), so secrets and internal details don't leak into stack traces or error reporting.

Multiple namespaces

To promote secrets between environments with a single login, derive a clone bound to a sibling namespace. The clone shares the already-acquired token, so no second login happens.

In header mode, swap the Enterprise namespace with withNamespace():

$prod = app(VaultService::class)->withNamespace('acme/prod');
$prod->write('myapp/database', $secrets);

In path mode, swap the full KV namespace path with withKvNamespace():

$prod = app(VaultService::class)->withKvNamespace('acme/prod/kv-secrets');
$prod->write('myapp/database', $secrets);

Each setter has a matching getter for reading what the instance is currently bound to — useful for deriving a sibling target from the current one:

Vault::namespace();    // current Enterprise namespace (header mode), e.g. "acme/dev"
Vault::kvNamespace();  // current KV namespace path (path mode), e.g. "acme/dev/kv-secrets"

What this package is not

It deliberately ships only auth + KV2 CRUD. Application-specific concepts belong in your app, not here.

Testing

composer install
./vendor/bin/pest

统计信息

  • 总下载量: 1
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 3
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-06-16

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固