ssk

package module
v0.5.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 13, 2026 License: MIT Imports: 20 Imported by: 0

README

sops-sakura-kms

A SOPS wrapper that enables SOPS (Secrets OPerationS) to use Sakura Cloud KMS for data key encryption.

This tool acts as a Vault Transit Engine compatible HTTP server, allowing SOPS to encrypt and decrypt data keys using Sakura Cloud KMS through the SOPS_VAULT_URIS environment variable.

Features

  • SOPS Integration: Seamlessly integrates SOPS with Sakura Cloud KMS
  • Vault Compatibility: Implements Vault Transit Engine compatible API
  • Automatic Configuration: Automatically configures SOPS with the correct Vault Transit URI
  • Transparent Operation: Works as a wrapper around SOPS, passing through all SOPS commands
  • Server-Only Mode: Can run as a standalone Vault Transit Engine compatible server without SOPS

Installation

Homebrew
brew install fujiwara/tap/sops-sakura-kms
Binary releases

Download the latest binary from the releases page.

From source
go install github.com/fujiwara/sops-sakura-kms/cmd/sops-sakura-kms@latest
GitHub Action

You can install sops-sakura-kms in your GitHub Actions workflows.

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: fujiwara/sops-sakura-kms@main
        with:
          version: 'v0.5.0' # or 'latest'
          # version-file: './.version'

This action sets up sops-sakura-kms and makes it available in the PATH. The sops command needs to be installed separately.

Container Image

You can use the provided container image: ghcr.io/fujiwara/sops-sakura-kms.

$ docker run --rm \
    -e SAKURA_ACCESS_TOKEN \
    -e SAKURA_ACCESS_TOKEN_SECRET \
    -e SAKURA_KMS_KEY_ID \
    -v $(pwd):/work -w /work \
    ghcr.io/fujiwara/sops-sakura-kms:v0.5.0 \
    -d secrets.enc.yaml

This image includes both sops-sakura-kms and sops commands.

Prerequisites

  • SOPS must be installed and available in your PATH
  • Sakura Cloud API credentials must be set in environment variables

Configuration

Set the following environment variables:

# Sakura Cloud API credentials
export SAKURA_ACCESS_TOKEN="your-access-token"
export SAKURA_ACCESS_TOKEN_SECRET="your-access-token-secret"

# Sakura Cloud KMS Resource ID (12-digit number as string, e.g., 123456789012)
# Required for encryption when hc_vault_transit_uri is not configured in .sops.yaml
# Not required for decryption (the key ID is stored in the encrypted file)
export SAKURA_KMS_KEY_ID="123456789012"

Note: For backward compatibility, the following alternative environment variable names are also supported. If both are set, SAKURA_* takes priority.

Primary (Recommended) Alternative
SAKURA_ACCESS_TOKEN SAKURACLOUD_ACCESS_TOKEN
SAKURA_ACCESS_TOKEN_SECRET SAKURACLOUD_ACCESS_TOKEN_SECRET
SAKURA_KMS_KEY_ID SAKURACLOUD_KMS_KEY_ID
Optional Environment Variables

You can customize the behavior with these optional environment variables:

# Run server-only mode without executing SOPS (default: false)
export SSK_SERVER_ONLY=true

# Server listen address (default: 127.0.0.1:8200)
export SSK_SERVER_ADDR="127.0.0.1:8200"

# Command to execute (default: sops)
export SSK_COMMAND="/path/to/sops"

Usage

Use sops-sakura-kms as a drop-in replacement for the sops command:

# Encrypt a file
sops-sakura-kms -e secrets.yaml > secrets.enc.yaml

# Decrypt a file
sops-sakura-kms -d secrets.enc.yaml

# Edit an encrypted file
sops-sakura-kms secrets.enc.yaml
How it works
  1. sops-sakura-kms starts a local Vault Transit Engine compatible HTTP server on 127.0.0.1:8200
  2. Sets required environment variables (VAULT_ADDR, VAULT_TOKEN)
  3. If SAKURA_KMS_KEY_ID is set, automatically sets the SOPS_VAULT_URIS environment variable to http://127.0.0.1:8200/v1/transit/encrypt/{key_id}
  4. Executes SOPS with the configured environment
  5. The server handles encryption/decryption requests from SOPS using Sakura Cloud KMS
Exit Code

sops-sakura-kms preserves the exit code from the wrapped command (SOPS or custom command specified by SSK_COMMAND).

  • If the wrapped command exits with code N, sops-sakura-kms also exits with code N
  • If an error occurs before executing the wrapped command (e.g., server startup failure), sops-sakura-kms exits with code 1
SOPS Configuration

You can use the standard SOPS configuration file (.sops.yaml) without specifying the hc_vault_transit_uri:

creation_rules:
  - path_regex: \.yaml$
    # No need to specify hc_vault_transit_uri - it's automatically configured via SOPS_VAULT_URIS

Note: The wrapper automatically sets the SOPS_VAULT_URIS environment variable, so you don't need to configure it manually in .sops.yaml or pass it as a command-line argument.

Using Multiple Keys

To use Sakura Cloud KMS alongside other encryption methods (e.g., age), explicitly specify hc_vault_transit_uri in .sops.yaml along with the other key configuration:

creation_rules:
  - path_regex: \.yaml$
    hc_vault_transit_uri: http://127.0.0.1:8200/v1/transit/keys/123456789012
    age: >-
      ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExample...

With this configuration, SOPS encrypts the data key with both Sakura Cloud KMS and age. Decryption succeeds if either key is available, providing redundancy across different key management systems.

Note: When using multiple keys, hc_vault_transit_uri must be specified in .sops.yaml because SOPS_VAULT_URIS alone does not allow SOPS to combine it with other key types in the creation rules.

Once a file is encrypted with multiple keys, decryption with non-Sakura Cloud KMS keys (e.g., age) can be done with the standard sops command directly — sops-sakura-kms wrapper is only needed when using the Sakura Cloud KMS key.

If you add or remove keys in .sops.yaml after a file has already been encrypted, run sops updatekeys to re-encrypt the data key with the updated set of keys:

sops-sakura-kms updatekeys secrets.enc.yaml
Server-Only Mode

You can run sops-sakura-kms as a standalone Vault Transit Engine compatible server without executing SOPS:

# Start server-only mode
export SSK_SERVER_ONLY=true
sops-sakura-kms

# The server will run until interrupted (Ctrl+C)

This mode is useful when:

  • You want to use the Vault Transit Engine API directly from your applications
  • You need to run the server as a separate service
  • You're testing or debugging the encryption/decryption API endpoints

In server-only mode, you can use the Vault API endpoints directly:

# Encrypt data
curl -X PUT http://127.0.0.1:8200/v1/transit/encrypt/123456789012 \
  -H "Content-Type: application/json" \
  -d '{"plaintext":"aGVsbG8gd29ybGQ="}'

# Decrypt data
curl -X PUT http://127.0.0.1:8200/v1/transit/decrypt/123456789012 \
  -H "Content-Type: application/json" \
  -d '{"ciphertext":"vault:v1:..."}'
Using with Terraform

Use terraform-provider-sops-sakura-kms to decrypt SOPS-encrypted files in Terraform. The provider starts the Vault Transit compatible server in-process, so no wrapper or background process is needed.

First, create an encrypted file with SOPS:

sops-sakura-kms -e secrets.yaml > secrets.enc.yaml

Then, use the encrypted file in Terraform:

# main.tf
terraform {
  required_providers {
    sops = {
      source = "fujiwara/sops-sakura-kms"
    }
  }
}

provider "sops" {
  key_id = "123456789012"  # Sakura Cloud KMS resource ID
}

data "sops_file" "secrets" {
  source_file = "secrets.enc.yaml"
}

output "secret_value" {
  value     = data.sops_file.secrets.data["password"]
  sensitive = true
}

See the provider documentation for details on authentication and configuration.

API Endpoints

The tool provides the following Vault Transit Engine compatible endpoints:

  • GET /health - Health check endpoint
  • PUT /v1/transit/encrypt/{key_id} - Encrypt data using specified KMS key
  • PUT /v1/transit/decrypt/{key_id} - Decrypt data using specified KMS key

Using as a Go Library

You can embed Sakura Cloud KMS-based SOPS decryption in your Go applications by combining RunServer with the SOPS decrypt package.

package main

import (
	"context"
	"encoding/json"
	"os"

	ssk "github.com/fujiwara/sops-sakura-kms"
	"github.com/getsops/sops/v3/decrypt"
)

type Config struct {
	DatabaseURL string `json:"database_url"`
	APIKey      string `json:"api_key"`
}

func main() {
	ctx := context.Background()

	// Start Vault Transit Engine compatible server
	addEnv, shutdown, err := ssk.RunServer(ctx, "127.0.0.1:8200", os.Getenv("SAKURA_KMS_KEY_ID"))
	if err != nil {
		panic(err)
	}
	defer shutdown(context.Background())

	// Set environment variables for SOPS library
	for k, v := range addEnv {
		os.Setenv(k, v)
	}

	// Decrypt SOPS-encrypted file
	plaintext, err := decrypt.File("secrets.enc.json", "json")
	if err != nil {
		panic(err)
	}

	var cfg Config
	if err := json.Unmarshal(plaintext, &cfg); err != nil {
		panic(err)
	}
	// Use cfg...
}
RunServer Function
func RunServer(ctx context.Context, addr, keyID string, opts ...Option) (map[string]string, func(context.Context) error, error)

Parameters:

  • ctx: Context for server operations
  • addr: Server listen address (e.g., "127.0.0.1:8200")
  • keyID: Sakura Cloud KMS resource ID (12-digit number)
  • opts: Functional options:
    • WithClient(saclient.ClientAPI): Use a pre-configured saclient instead of environment variables
    • WithCipher(Cipher): Use a custom Cipher implementation (for testing)

Returns:

  • map[string]string: Environment variables for SOPS (VAULT_ADDR, VAULT_TOKEN, and SOPS_VAULT_URIS if keyID is non-empty)
  • func(context.Context) error: Shutdown function to stop the server
  • error: Any error that occurred during startup

Note: Without WithClient, Sakura Cloud API credentials (SAKURA_ACCESS_TOKEN, SAKURA_ACCESS_TOKEN_SECRET) must be set in environment variables.

Development

Running Tests
# Run all tests
go test ./...

# Run tests with actual Sakura Cloud KMS (requires credentials and KEY_ID)
KEY_ID=123456789012 go test ./...
Building
make build

License

MIT License - see LICENSE file for details

Author

FUJIWARA Shunichiro

Documentation

Overview

Package ssk provides a Vault Transit Engine compatible API server that enables SOPS to use Sakura Cloud KMS for data key encryption.

Wrapper Mode

The primary use case is as a SOPS wrapper via the command-line tool. See the cmd/sops-sakura-kms package for the CLI entrypoint.

Library Usage

You can also use this package as a Go library to embed Sakura Cloud KMS-based SOPS decryption in your applications. Use RunServer to start the Vault Transit Engine compatible server, then use the SOPS decrypt package to decrypt files.

addEnv, shutdown, err := ssk.RunServer(ctx, "127.0.0.1:8200", keyID) // uses env vars

Or with a pre-configured saclient:

addEnv, shutdown, err := ssk.RunServer(ctx, "127.0.0.1:8200", keyID, ssk.WithClient(client))
if err != nil {
    return err
}
defer shutdown(context.Background())

for k, v := range addEnv {
    os.Setenv(k, v)
}

plaintext, err := decrypt.File("secrets.enc.yaml", "yaml")

Environment Variables

The following environment variables must be set:

  • SAKURACLOUD_ACCESS_TOKEN: Sakura Cloud API access token
  • SAKURACLOUD_ACCESS_TOKEN_SECRET: Sakura Cloud API access token secret

For wrapper mode, also set:

  • SAKURACLOUD_KMS_KEY_ID: Sakura Cloud KMS resource ID (12-digit number)

Index

Constants

View Source
const (
	VaultPrefix    = "vault:v1:"
	KeyIDPathParam = "key_id"

	// ExitCodeError is the exit code returned when an error occurs in the application.
	ExitCodeError = 1
)

Variables

View Source
var IsStdinTerminal = func() bool {
	return isatty.IsTerminal(os.Stdin.Fd())
}

IsStdinTerminal reports whether stdin is a terminal. It is a package variable so tests can substitute their own check; production callers should leave it alone.

View Source
var Version = "v0.5.1"

Functions

func DecryptHandlerFunc

func DecryptHandlerFunc(cipher Cipher) func(w http.ResponseWriter, r *http.Request)

DecryptHandlerFunc returns an HTTP handler for Vault Transit Engine decrypt endpoint.

func EncryptHandlerFunc

func EncryptHandlerFunc(cipher Cipher) func(w http.ResponseWriter, r *http.Request)

EncryptHandlerFunc returns an HTTP handler for Vault Transit Engine encrypt endpoint.

func NewMux

func NewMux(cipher Cipher) *http.ServeMux

NewMux creates a new HTTP ServeMux with Vault Transit Engine compatible API endpoints.

func RunServer added in v0.3.0

func RunServer(ctx context.Context, addr, keyID string, opts ...Option) (map[string]string, func(context.Context) error, error)

RunServer starts the Vault Transit Engine compatible API server. Without options, it uses Sakura Cloud KMS with credentials from environment variables. Use WithCipher to provide a custom cipher, or WithClient to provide a pre-configured saclient. Returns environment variables to configure SOPS, a shutdown function, and any error that occurred.

func RunWrapper

func RunWrapper(ctx context.Context, args []string) (int, error)

RunWrapper starts a Vault Transit Engine compatible API server and executes a command. It automatically configures SOPS to use Sakura Cloud KMS via SOPS_VAULT_URIS environment variable. Requires SAKURA_KMS_KEY_ID environment variable to be set. Returns the exit code of the executed command and any error that occurred.

func ShowVersion added in v0.4.0

func ShowVersion(ctx context.Context, w io.Writer) (int, error)

Types

type Cipher

type Cipher interface {
	// Encrypt encrypts plaintext using the specified key ID.
	// Returns base64-encoded ciphertext string.
	Encrypt(ctx context.Context, keyID string, plaintext []byte) (string, error)
	// Decrypt decrypts ciphertext using the specified key ID.
	// Accepts base64-encoded ciphertext string and returns plaintext bytes.
	Decrypt(ctx context.Context, keyID string, ciphertext string) ([]byte, error)
}

Cipher defines the interface for encryption and decryption operations.

type Env added in v0.0.5

type Env struct {
	KMSKeyID   string `env:"SAKURA_KMS_KEY_ID,SAKURACLOUD_KMS_KEY_ID"`
	ServerOnly bool   `env:"SSK_SERVER_ONLY" default:"false"`
	ServerAddr string `env:"SSK_SERVER_ADDR" default:"127.0.0.1:8200"`
	Command    string `env:"SSK_COMMAND" default:"sops"`
}

func LoadEnv added in v0.2.0

func LoadEnv() (*Env, error)

LoadEnv loads environment variables into an Env struct based on struct tags. It reads the "env" tag for the environment variable name, "default" tag for default values, and "required" tag for required fields.

type Option added in v0.4.1

type Option func(*serverOptions)

Option is a functional option for RunServer.

func WithCipher added in v0.4.1

func WithCipher(c Cipher) Option

WithCipher sets a custom Cipher implementation. Useful for testing.

func WithClient added in v0.4.1

func WithClient(c saclient.ClientAPI) Option

WithClient sets a saclient.ClientAPI for creating the KMS cipher. This takes precedence over the default environment variable-based client.

type SakuraKMS

type SakuraKMS struct {
	// contains filtered or unexported fields
}

SakuraKMS implements Cipher interface using Sakura Cloud KMS.

func NewSakuraKMS

func NewSakuraKMS() (*SakuraKMS, error)

NewSakuraKMS creates a new SakuraKMS instance. It reads credentials from environment variables (SAKURACLOUD_ACCESS_TOKEN, SAKURACLOUD_ACCESS_TOKEN_SECRET).

func NewSakuraKMSWithClient added in v0.4.1

func NewSakuraKMSWithClient(c saclient.ClientAPI) (*SakuraKMS, error)

NewSakuraKMSWithClient creates a new SakuraKMS instance with the given saclient.ClientAPI.

func (*SakuraKMS) Decrypt

func (c *SakuraKMS) Decrypt(ctx context.Context, keyID string, ciphertext string) ([]byte, error)

Decrypt decrypts ciphertext using Sakura Cloud KMS.

func (*SakuraKMS) Encrypt

func (c *SakuraKMS) Encrypt(ctx context.Context, keyID string, plaintext []byte) (string, error)

Encrypt encrypts plaintext using Sakura Cloud KMS with AES-256-GCM algorithm.

type VaultDecryptRequest

type VaultDecryptRequest struct {
	Ciphertext string `json:"ciphertext"`
}

VaultDecryptRequest represents the request body for Vault Transit Engine decrypt API. Ciphertext must include "vault:v1:" prefix.

type VaultDecryptResponse

type VaultDecryptResponse struct {
	Plaintext string `json:"plaintext"`
}

VaultDecryptResponse represents the response body for Vault Transit Engine decrypt API. Plaintext is returned as base64-encoded string.

type VaultEncryptRequest

type VaultEncryptRequest struct {
	Plaintext string `json:"plaintext"`
}

VaultEncryptRequest represents the request body for Vault Transit Engine encrypt API. Plaintext must be base64-encoded string.

type VaultEncryptResponse

type VaultEncryptResponse struct {
	Ciphertext string `json:"ciphertext"`
}

VaultEncryptResponse represents the response body for Vault Transit Engine encrypt API. Ciphertext includes "vault:v1:" prefix followed by the encrypted data.

type VaultErrorResponse added in v0.0.3

type VaultErrorResponse struct {
	Errors []string `json:"errors"`
}

VaultErrorResponse represents the error response body for Vault API. Errors is an array of error message strings.

Directories

Path Synopsis
cmd
sops-sakura-kms command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL