How to Configure Security for API Keys and Authentication in OpenViking

OpenViking stores runtime secrets in a YAML configuration file parsed by config.LoadConfig, where each plugin declares required authentication parameters via GetConfigParams, validates them through the Validate method using helpers like config.RequireString, and injects them into HTTP headers at request time without logging sensitive values.

OpenViking is an open-source agentic filesystem that requires secure handling of third-party API credentials for services like OpenAI and AWS. To configure security for API keys and authentication in OpenViking, administrators define secrets in a structured YAML file that the server loads at startup, ensuring credentials are validated before any plugin becomes active.

Declaring Secret Parameters in Plugin Configuration

OpenViking's plugin architecture requires each component to advertise its configuration schema through the GetConfigParams method. This declarative approach ensures that sensitive values like API keys are explicitly marked as required strings before the server initializes.

GPTFS Plugin Example

In third_party/agfs/agfs-server/pkg/plugins/gptfs/gptfs.go, the GPTFS plugin defines its authentication parameter as follows:

{
    Name:        "api_key",
    Type:        "string",
    Required:    true,
    Description: "API key for OpenAI‑compatible service",
},

This declaration signals to the configuration loader that the plugin cannot function without this specific secret.

Validating API Keys at Startup

When the server loads a plugin, it invokes the Validate method to ensure all required secrets are present and properly formatted. The GPTFS implementation in gptfs.go uses validation helpers from the config package:

allowedKeys := []string{"api_host", "api_key", "mount_path", "workers"}
if err := config.ValidateOnlyKnownKeys(cfg, allowedKeys); err != nil {
    return err
}
if _, err := config.RequireString(cfg, "api_key"); err != nil {
    return err
}

The config.RequireString function, defined in third_party/agfs/agfs-server/pkg/config/config.go, aborts startup with an error if the api_key field is missing or empty. This prevents the plugin from running with invalid or undefined credentials.

Unit Test Verification

The validation logic is verified in third_party/agfs/agfs-server/pkg/plugins/gptfs/gptfs_test.go:

func TestGptfsValidateRequiresApiKey(t *testing.T) {
    cfg := map[string]interface{}{
        "api_host":   "https://example.com",
        "mount_path": "/tmp/gptfs",
        // "api_key" omitted on purpose
    }
    g := &Gptfs{}
    if err := g.Validate(cfg); err == nil {
        t.Fatalf("expected error for missing api_key")
    }
}

Runtime Injection and Request Security

After validation, the plugin stores the secret in memory and injects it into outbound HTTP requests. The GPTFS driver constructs the Authorization header in gptfs.go without exposing the value in logs:

req.Header.Set("Authorization", "Bearer "+d.apiKey)

This implementation ensures the bearer token never appears in error messages or log files—only the HTTP client receives the credential.

YAML Configuration File Structure

The server reads runtime settings from a YAML file specified via the -c flag. Secrets reside under the plugins section, nested within each plugin's config object.

Basic Configuration Example

server:
  address: ":8080"
  log_level: "info"

plugins:
  gptfs:
    enabled: true
    config:
      api_host: "https://api.openai.com/v1"
      api_key:  "YOUR_OPENAI_API_KEY"
      mount_path: "/agents/gptfs"
      workers: 4

Only the api_key field requires protection as a secret value.

Environment Variable Substitution

While OpenViking does not natively expand environment variables inside the YAML parser, deployment pipelines can substitute placeholders before startup:

plugins:
  gptfs:
    enabled: true
    config:
      api_key: "${GPT_API_KEY}"   # placeholder for substitution

Deploy with an environment variable:

export GPT_API_KEY="sk-abcdef1234567890"
./agfs-server -c ./config.yaml

Multi-Provider Authentication: S3FS Example

The S3FS plugin demonstrates alternative secret handling patterns for AWS credentials. Located in third_party/agfs/agfs-server/pkg/plugins/s3fs/s3fs.go, this implementation accepts explicit configuration values while falling back to standard AWS environment variables.

The plugin declares optional fields in GetConfigParams:

{
    Name:        "access_key_id",
    Type:        "string",
    Required:    false,
    Description: "AWS access key ID (uses env AWS_ACCESS_KEY_ID if not provided)",
},
{
    Name:        "secret_access_key",
    Type:        "string",
    Required:    false,
    Description: "AWS secret access key (uses env AWS_SECRET_ACCESS_KEY if not provided)",
},

When access_key_id or secret_access_key are omitted from the YAML, the plugin reads from AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY at runtime, providing flexibility for hybrid deployment scenarios.

Security Best Practices

To harden authentication in production environments:

  • Never commit real secrets – Store the YAML file outside version control or use placeholder syntax like ${API_KEY} that your CI/CD pipeline populates at deployment time.
  • Restrict file permissions – Set the configuration file to be readable only by the user account running the agfs-server process (e.g., chmod 600 config.yaml).
  • Rotate credentials regularly – Update the api_key value in the YAML file and restart the server; the Validate step guarantees the new key is present before the plugin accepts traffic.
  • Audit logging behavior – The OpenViking source code explicitly avoids logging secret values (see log.Infof usage in gptfs.go), but verify that custom plugins follow this pattern.

Summary

  • OpenViking uses a centralized YAML configuration loaded by config.LoadConfig in third_party/agfs/agfs-server/pkg/config/config.go to manage secrets.
  • Plugins declare required authentication parameters via GetConfigParams and enforce presence through config.RequireString during the Validate phase.
  • Secrets are injected into HTTP headers at request time (e.g., Authorization: Bearer) without appearing in server logs.
  • The GPTFS plugin (gptfs.go) requires explicit api_key values, while S3FS (s3fs.go) supports both YAML-defined credentials and environment variable fallbacks.
  • External secret management is achieved through placeholder substitution in the YAML file during deployment, not through native environment variable expansion.

Frequently Asked Questions

How does OpenViking validate that an API key is present before starting?

OpenViking invokes the Validate method on each plugin after loading the configuration. For the GPTFS plugin, this method calls config.RequireString(cfg, "api_key") in third_party/agfs/agfs-server/pkg/plugins/gptfs/gptfs.go, which returns an error and aborts server startup if the key is missing or empty. This ensures no plugin runs without proper authentication credentials.

Can I use environment variables instead of hardcoding API keys in the YAML file?

OpenViking does not natively evaluate environment variables inside the YAML parser. However, you can use placeholder syntax like ${GPT_API_KEY} in your config.yaml and expand these values using your shell or CI/CD pipeline before startup. The S3FS plugin alternatively reads standard AWS environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) at runtime if the YAML configuration omits these fields.

Where are API keys stored once the server loads them?

After validation, the API key is stored as a private field in the plugin struct (e.g., d.apiKey in the GPTFS driver). The value persists in memory and is injected into the Authorization header for each outbound HTTP request in third_party/agfs/agfs-server/pkg/plugins/gptfs/gptfs.go. The secret never appears in log files or error messages returned to clients.

To rotate credentials, update the api_key value in your YAML configuration file and restart the agfs-server process. The server re-runs the Validate method during startup, confirming the new key is present and properly formatted before activating the plugin. There is no hot-reload mechanism; a restart is required to apply new secrets.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →