返回资讯中心
外部精选
软件工程
#开发者实时流

Nops: Read SOPS-encrypted secrets in .NET without the sops binary

Nops reads SOPS-encrypted secrets straight into .NET configuration. There is no sops binary, no subprocess and no plaintext on disk.

Hacker News 最新atulmish2026/10/25 · 11 天前18 分钟阅读

以下正文同步自 Hacker News 最新,版权归原站所有,已转换为易读排版。

Documentation  ·  Quickstart  ·  Samples  ·  Changelog

Nops reads SOPS-encrypted secrets straight into .NET configuration. There is no sops binary, no subprocess and no plaintext on disk.

You keep encrypting and editing secrets with the sops CLI as usual and commit the encrypted files. Your app decrypts them in-process at startup:

builder.Configuration.AddSops("secrets.sops.yaml");

Nops finds your age keys the same way sops does, decrypts the data key (age, PGP, AWS KMS, GCP KMS, Azure Key Vault, HashiCorp Vault), checks the file's MAC, and exposes the values through IConfiguration, ready for IOptions<T>.

SOPS is a good way to keep secrets in git: values are encrypted, keys stay readable, diffs are reviewable, and access is controlled with age, PGP or a cloud KMS. But SOPS is a Go command-line tool, and a .NET app cannot read a SOPS file by itself. In practice teams reach for one of these:

Nops is the missing piece for .NET: a library that reads the same SOPS files in-process. There is no sops binary at runtime, no subprocess and no plaintext on disk. Your app opens the encrypted file with the key it already has, verifies the file's MAC, and exposes the values as ordinary IConfiguration, so IOptions<T>, layering, environment-variable overrides and reload on change all work as usual.

You keep everything good about SOPS: your team still edits secrets with the sops CLI, the files in git don't change, and access is still decided by age, PGP or KMS keys. Nops only replaces the "decrypt it somehow before the app starts" step.

Use Nops if you have a .NET app, you want secrets encrypted in git, and you would rather not ship the sops binary or run a decrypt step. Look elsewhere if you need to create or edit encrypted files from code (Nops only decrypts, use the sops CLI), you are not on .NET, or you already run a secret store and are happy with it.

dotnet add package Nops.Configuration # IConfiguration provider (includes Nops.Core) dotnet add package Nops.Core # Decryption API only

Package Use it for

Nops.Core Decrypting files directly; age and PGP keys

Nops.Configuration IConfiguration provider with reload on change (ASP.NET Core, generic host, console)

Nops.Core.AwsKms AWS KMS keys

Nops.Core.GcpKms Google Cloud KMS keys

Nops.Core.Azkv Azure Key Vault keys

Nops.Core.Vault HashiCorp Vault Transit keys

Nops.Templates dotnet new templates for a web API and a worker service that load SOPS secrets

From version 1.1.0 the libraries target .NET 8 and .NET 10, the two long-term support releases. Applications on .NET 9 use the .NET 8 build.

dotnet new install Nops.Templates dotnet new nops-webapi -n MyApi cd MyApi && dotnet run

The template ships a demo secrets file and a TEST-ONLY key so it runs immediately. Its README explains how to switch to your own key. See also the samples and the hosting guide (console, worker service, ASP.NET Core, Azure Functions).

age-keygen -o ~/.config/sops/age/keys.txt # once per machine sops -e --age "$(age-keygen -y ~/.config/sops/age/keys.txt)" secrets.yaml > secrets.sops.yaml

ASP.NET Core / generic host

using Nops.Configuration;

var builder = WebApplication.CreateBuilder(args); // or Host.CreateApplicationBuilder(args)

builder.Configuration.AddSops("secrets.sops.yaml", opts => { opts.WatchForChanges = true; // IOptionsMonitor<T> sees rotated secrets });

builder.Services.AddOptions<DatabaseOptions>() .BindConfiguration("Database") .ValidateOnStart();

Database.Password in the YAML becomes Database:Password in IConfiguration, the same as with appsettings.json.

using Nops.Core;

var bytes = await File.ReadAllBytesAsync("secrets.sops.yaml");

// Flattened "a:b:c" keys IReadOnlyDictionary<string, string> values = await SopsFile.DecryptToDictionaryAsync(bytes, "yaml", new SopsOptions());

// Or bind to a type var settings = await SopsFile.DecryptAsync<MySettings>(bytes, "yaml", new SopsOptions());

Plain config plus one secrets file

Most apps keep appsettings.json in plaintext and put only the secrets in a SOPS file. Sources layer in the order you add them, so the SOPS values override the plaintext file and environment variables still win:

builder.Configuration .AddSops("secrets.sops.yaml") .AddEnvironmentVariables() .AddCommandLine(args);

Config diffs stay readable in review and only the secrets are encrypted. See Deploying with Nops for Kubernetes and Docker setups, partial encryption with encrypted_regex, and key rotation.

Source How

sops environment (default) SOPS_AGE_KEY, SOPS_AGE_KEY_FILE, then $XDG_CONFIG_HOME/sops/age/keys.txt (~/.config/…, ~/Library/Application Support/… or %AppData%\…). Turn off with UseSopsEnvironment = false.

Explicit age keys opts.AgeIdentities = ["AGE-SECRET-KEY-1…", "/run/secrets/age.txt"] (keys or key-file paths)

PGP opts.PgpKeys = [(File.ReadAllBytes("key.asc"), passphrase)] (armored or binary secret key)

Cloud KMS / Vault opts.MasterKeys = [new AwsKmsMasterKey("arn:aws:kms:…")]. See Cloud KMS setup.

In containers, mount the age key as a secret and point SOPS_AGE_KEY_FILE at it. Files with several key groups (Shamir shamir_threshold) work as soon as enough of the keys are available.

The file's MAC is verified before any value is returned, so a tampered or truncated file fails instead of loading partly.

Decrypted values live in memory only. Nops never writes plaintext to disk and starts no subprocess.

Key material is read from the same places as the sops CLI, or from a cloud KMS so no key is on disk at all.

Optional = true tolerates a missing file only. A present file that fails to decrypt or fails its MAC check always throws, so a required secret never silently disappears.

To report a vulnerability, see SECURITY.md.

Encrypting or editing. Nops only decrypts; use the sops CLI to create and change files.

SOPS_AGE_KEY_CMD, age SSH identities, age plugins, passphrase (scrypt) and post-quantum age recipients.

PGP keys from a gpg keyring or agent: pass the secret key bytes instead.

Relative file paths are resolved against the current working directory.

Quickstart: first decrypt, typed binding, samples

Configuration reference: every option, key flattening, reload, errors

Deploying with Nops: config layout, Kubernetes and Docker, key rotation, troubleshooting

Hosting guide: console, worker service, ASP.NET Core and Azure Functions

Docker and distroless images: run without a shell or the sops binary

Kubernetes and GitOps: how Nops fits with Flux, Argo CD and in-cluster decryption

Migrating to Nops: from sops -d in CI, user-secrets and plain environment variables

Comparison: Nops and the other ways to use SOPS from .NET

Security model: guarantees, how the implementation was verified, and its limits

Cloud KMS setup: AWS, GCP, Azure, Vault

Test keys: how the fixtures are generated

Samples: console, minimal API and layered-config apps you can run

Contributing

Issues and pull requests are welcome. See CONTRIBUTING.md. To report a vulnerability, follow SECURITY.md instead of opening an issue.

dotnet build Nops.slnx dotnet test Nops.slnx

Cloud integration tests are skipped unless their environment is available (for example AWS_LIVE_TEST=1 with LocalStack).

MIT. See LICENSE. Nops reimplements the SOPS file format and cryptography in C# without copying Go code. SOPS itself is MPL-2.0.

正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。

打开原文
去社区讨论 →