scala-vault
scala-vault copied to clipboard
Hashicorp Vault Scala Libraries
Vault Scala Library
Scala library for working with Hashicorp Vault.
This library has three modules:
Install with SBT
Add the following to your sbt project/plugins.sbt file:
addSbtPlugin("me.lessis" % "bintray-sbt" % "0.3.0")
Then add the following to your build.sbt
resolvers += Resolver.bintrayRepo("janstenpickle", "maven")
libraryDependencies += "janstenpickle.vault" %% "vault-core" % "0.4.0"
libraryDependencies += "janstenpickle.vault" %% "vault-auth" % "0.4.0"
libraryDependencies += "janstenpickle.vault" %% "vault-manage" % "0.4.0"
Usage
Simple setup:
import java.net.URL
import janstenpickle.vault.core.AppRole
import janstenpickle.vault.core.VaultConfig
import janstenpickle.vault.core.WSClient
val config = VaultConfig(WSClient(new URL("https://localhost:8200")), "token")
val appRoleConfig = VaultConfig(WSClient(new URL("https://localhost:8200")), AppRole("roleId", "secretId"))
WSClient
This library uses the Dispatch, a lightweight async HTTP client to communicate with Vault.
Responses
All responses from Vault are wrapped in an asynchronous Result. This allows any errors in the response are captured separately from the failure of the underlying future.
Reading and writing secrets
import java.net.URL
import janstenpickle.vault.core.AppRole
import janstenpickle.vault.core.VaultConfig
import janstenpickle.vault.core.WSClient
import janstenpickle.vault.core.Secrets
val config = VaultConfig(WSClient(new URL("https://localhost:8200")), AppRole("roleId", "secretId"))
val secrets = Secrets(config, "secret")
Getting a secret
val response = secrets.get("some_secret")
// Unsafely evaluate the Task
println(response.unsafePerformSyncAttempt)
Setting a secret
val response = secrets.set("some_secret", "some_value")
Setting a secret under a different sub key
val response = secrets.set("some_secret", "some_key", "some_value")
Setting a secret as a map
val response = secrets.set("some_secret", Map("k1" -> "v1", "k2" -> "v2"))
Getting a map of secrets
val response = secrets.getAll("some_secret")
Listing all secrets
val response = secrets.list
Authenticating a username/password
import java.net.URL
import janstenpickle.vault.core.WSClient
import janstenpickle.vault.auth.UserPass
val userPass = UserPass(WSClient(new URL("https://localhost:8200")))
val ttl = 10 * 60
val response = userPass.authenticate("username", "password", ttl)
The response will contain the fields as per the Vault documentation.
Multitenant username/password auth
This requires that userpass authentication has been enabled on separate path to the default of userpass. Instructions of how to do this are documented below. By doing this credientials for different tenants may be stored separately within Vault.
val response = userPass.authenticate("username", "password", ttl, "clientId")
Managing Vault
This library also provides some limited management functionality for Vault around authenctiation, mounts and policy.
Authentication Management
import java.net.URL
import janstenpickle.vault.core.AppRole
import janstenpickle.vault.core.VaultConfig
import janstenpickle.vault.core.WSClient
import janstenpickle.vault.manage.Auth
val config = VaultConfig(WSClient(new URL("https://localhost:8200")), AppRole("roleId", "secretId"))
val auth = Auth(config)
// enable an auth backend
val enable = auth.enable("auth_type")
// disable an auth backend
val disable = auth.disable("auth_type")
The enable function can also take an optional mount point and description, the mount point is useful when setting up multitenant userpass backend as the mount point will correspond to the client ID.
val response = auth.enable("auth_type", Some("client_id"), Some("description"))
Example Usage - Multitenant Authentication Service
Using this library it is very simple to set up a token authentication service for ReST API authentication made up of three components:
- Vault
- Thin authentication endpoint
- API service
The sequence diagram below shows how this may be constructed:

Code Examples for Authentication Service
The exmaples below show how clients can be set up, users authenticated and tokens validated:
Client Administration
import janstenpickle.vault.core.VaultConfig
import janstenpickle.vault.manage.Auth
class ClientAuth(config: VaultConfig) {
val auth = Auth(config)
def create(clientId: String, clientName: String): AsyncResult[WSResponse] = auth.enable("userpass", Some(clientId), Some(clientName))
def delete(clientId: String): AsyncResult[WSResponse] = auth.disable(clientId)
}
User Administration
import janstenpickle.vault.core.VaultConfig
import janstenpickle.vault.manage.UserPass
class UserAdmin(config: VaultConfig, ttl: Int) {
val userPass = UserPass(config)
def create(username: String, password: String, clientId: String, policies: Option[List[String]] = None): AsyncResult[WSResponse] =
userPass.create(username, password, ttl, policies, clientId)
def setPassword(username: String, password: String, clientId: String): AsyncResult[WSResponse] =
userPass.setPassword(username, password, clientId)
def setPolicies(username: String, policies: List[String], clientId: String): AsyncResult[WSResponse] =
userPass.setPolicies(username, policies, clientId)
def delete(username: String, clientId: String): AsyncResult[WSResponse] = userPass.delete(username, clientId)
}
User Authentication
import janstenpickle.vault.core.WSClient
import janstenpickle.vault.manage.Auth
class UserAuth(wsClient: WSClient, ttl: Int) {
val userPass = UserPass(wsClient)
// returns only the token
def auth(username: String, password: String, clientId: String): AsyncResult[String] =
userPass.authenticate(username, password, ttl, clientId).map(_.client_token)
}
Develop scala-vault
Testing
sbt clean startVaultTask coverage test it:test coverageReport