Getting Started with the OIT Vault Service


OIT offers a managed Hashicorp Vault Enterprise service as a secrets management solution for campus IT. The service is currently integrated into a number of campus services, such as the CLS Puppet ecosystem, and additional service integrations are available at the cost of a license upon request. Contact OIT_IWS@help.ncsu.edu for more information about integrating Vault into new services.

Requesting Access

All users requiring access to the OIT Vault service must be added to the access list in order to log in. New users must submit a request to OIT_IWS@help.ncsu.edu requesting access. Please include a detailed description of how you'll be using the service along with your request. All access is currently limited to the use of .admin accounts, so you'll also need a .admin account provisioned by your local IT staff to continue with the request.

Interacting with Vault

Accessing the Web Interface

Authorized users may access the Vault web UI at https://vault.oit.ncsu.edu:8200/

Users MUST be connected to the Staff / OIT Staff VPN to access the service, or have made specific arrangements with OIT for workstation access.
General access from campus networks is currently not permitted.

To sign in, access the web UI via the URL above, and enter "NCSU" in the namespace field on the sign-in page.
Once the namespace has been updated, you should see a blue "Sign in with Azure" button at the bottom of the sign-in screen.
Clicking the button will prompt for an Entra ID login. Log in with your .admin account to continue.

**Note:** If you're already logged in to Entra ID with just your Unity account, the login will an error that your account doesn't have access. Using an incognito window, or using office.com to add your .admin account to your existing Entra ID session are recommended to proceed.

Namespaces and Secret Engines

The namespace switcher at the top left of the page can be used to switch between contexts for the various services integrated with Vault. For example, CLS tenants should see a "CLS" namespace, etc. 

After switching to the appropriate namespace for the desired service, you should see a Secret Engine named after your unit. Click on it to view and edit your secrets for that service.

Secrets are contextualized to a specific service based on the namespace, so a secret defined in a given namespace can ONLY be read by the corresponding service.

**Note:** There is a permissions quirk which results in a banner at the top of the page saying you don't have permissions to the namespace. This message is safe to close and ignore.

Defining Secrets

Secrets are defined within your unit's Secret Engine, which is named after your unit (e.g. OITIWS, or ECE).

Each Secret entry within the Engine consists of a set of Key-Value pairs, and keeps a history of the last 10 versions.

The consuming service integrated with Vault can request either the full set of KV pairs (usually in the form of a Dictionary or Hash), or a specific value for a single key.

Secrets can be organized into "folders" by including slashes in the Secret name (e.g. "production/my-service/database", or "staging/my-service/email")

**Note:** Although the web interface will group Secrets into a folder-like structure, there is no way to mass-delete an entire folder. After each entry in the folder is deleted, the folder itself will disappear.

Currently Integrated Campus Services

ACME Certificate Management

OIT offers an automated certificate enrollment service to campus, which pushes its certs to Vault. Other integrated services can be configured to pull certificates and keys from Vault to automatically handle installing and rotating TLS certificates on a regular basis.

See the documentation on the associated GitHub repository for more details: https://github.com/ncstate-oit-iws/acme-cert-configs

CLS Puppet Ecosystem

All CLS tenants may pull secrets from Vault to use in configuration management through the Puppet/Hiera integration in the CLS Puppet ecosystem.

To get started, you first need to add a new section to your `hiera.yaml` file in your control repository:

hierarchy:
  - name: "Vault Lookup"
    lookup_key: hiera_vault
    options:
      confine_to_keys:
        - "^vault:.*" # Change this to affect the prefix when looking up Vault secrets
      strip_from_keys:
        - "^vault:" # MUST match your chosen prefix
      ssl_verify: true
      strict_mode: true # When enabled, the catalog will fail if it can't pull a value. When false, it will continue with a blank value
      address: https://vault.oit.ncsu.edu:8200
      token: /etc/puppetlabs/puppet/vault_token.txt
      v1_lookup: false
      v2_guess_mount: false
      mounts:
        CLS:
          - data

The commented values are configurable, but these are the recommended defaults. The rest of the config is required as-is.
We highly recommend using strict_mode, as this protects against a service outage or network failure between the CLS puppet servers and Vault.
When strict_mode is disabled, any missing secret or communication failure talking to Vault will return a blank value instead of causing a catalog error.

The prefix affects the hiera key prefix used when looking up values to denote you expect the value to come from Vault.
You can set this to whatever makes sense to you, but we find that "vault:" is an intuitive default.

To pull a value from Vault, substitute the value like this in your hiera:
example_profile::something_sensitive: "%{alias('vault:path/to/your/secret_name'.'key_name')}" # Pull single value from secret by key
example_profile::some_block_config: "%{alias('vault:path/to/your/secret_name')}" # Pull the whole secret as a hash

You can use dot notation to target specific keys inside the secret to pull just that value, or omit the key name to pull the whole secret as a hash.

For example,iIf we have a database password we want to pull from Vault, we may have the following Vault secret:
admin/NCSU/CLS/EXAMPLE/production/database
---
username: root
password: s3cret

In hiera, we'd access those values like this:
example_profile::database::root_username: "%{alias('vault:production/database'.'username')}"
example_profile::database::root_password: "%{alias('vault:production/database'.'password')}"

The Vault lookup can replace your existing EYAML "ENC[]" blocks:
# Before:
example_profile::database::root_password: ENC[PKCS7,MIIBeQYJKoZIhvc...]

# After:
example_profile::database::root_password: "%{alias('vault:production/database'.'password')}"