Kubernetes secrets support for Ciris
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
notes Add 0.10 release notes Nov 15, 2018
project Update sbt to 1.2.6 Oct 28, 2018
src/main/scala/ciris Change to detech when key is missing Nov 15, 2018
.gitignore Initial commit Jan 26, 2018
.scalafmt.conf Initial commit Jan 26, 2018
build.sbt Update ciris to 0.12.0 Nov 14, 2018
license.txt Initial commit Jan 26, 2018
readme.md
version.sbt Setting version to 0.11-SNAPSHOT Nov 15, 2018

readme.md

Ciris Kubernetes

Kubernetes secrets support for Ciris using the official Kubernetes Java client.

Getting Started

To get started with sbt, simply add the following lines to your build.sbt file.

resolvers += Resolver.bintrayRepo("ovotech", "maven")

libraryDependencies += "com.ovoenergy" %% "ciris-kubernetes" % "0.10"

The library is published for Scala 2.11 and 2.12.

Usage

Start with import ciris.kubernetes._, create an ApiClient, and register any authenticators. You can then set the namespace for your secrets with secretInNamespace, like in the following example. You can then load secrets by specifying the secret name. If there is more than one entry for the secret, you can also specify the key to retrieve.

import cats.effect.IO
import ciris._
import ciris.cats.effect._
import ciris.kubernetes._
import ciris.syntax._

final case class Config(
  appName: String,
  apiKey: Secret[String],
  username: String,
  timeout: Int
)

val config: IO[Config] =
  for {
    _ <- registerGcpAuth[IO]
    apiClient <- defaultApiClient[IO]
    secret = secretInNamespace("secrets", apiClient)
    config <- loadConfig(
      secret[Secret[String]]("apiKey"), // Key can be omitted if secret has only one entry
      secret[String]("username"),
      secret[Int]("defaults", "timeoutt") // Key is necessary if secret has multiple entries
    ) { (apiKey, username, timeout) =>
      Config(
        appName = "my-api",
        apiKey = apiKey,
        username = username,
        timeout = timeout
      )
    }.orRaiseThrowable
  } yield config

In the example above, the apiKey secret is missing, the username secret has multiple entries, and timeout was accidentally misspelled. The loadConfig method returns an IO[Either[ConfigErrors, Config]], and we raise ConfigErrors as an exception with orRaiseThrowable.

We've now described how to load the configuration, so let's try to actually load it. We're only using unsafeRunSync for demonstration purposes here, you should normally never use it. As the example shows, error messages give detailed information on what went wrong.

config.unsafeRunSync()
// ciris.ConfigException: configuration loading failed with the following errors.
//
//   - Missing kubernetes secret [namespace = secrets, name = apiKey].
//   - There is more than one entry available for kubernetes secret [namespace = secrets, name = username], please specify which key to use; available keys are: admin, user.
//   - Kubernetes secret [namespace = secrets, name = defaults, key = timeoutt] exists but there is no entry with key [timeoutt]; available keys are: port, timeout.
//
//   at ciris.ConfigException$.apply(ConfigException.scala:34)
//   at ciris.ConfigErrors$.toException$extension(ConfigErrors.scala:128)
//   at ciris.syntax$EitherConfigErrorsFSyntax$.$anonfun$orRaiseThrowable$1(syntax.scala:71)
//   at cats.effect.internals.IORunLoop$.liftedTree3$1(IORunLoop.scala:207)
//   at cats.effect.internals.IORunLoop$.step(IORunLoop.scala:207)
//   at cats.effect.IO.unsafeRunTimed(IO.scala:307)
//   at cats.effect.IO.unsafeRunSync(IO.scala:242)
//   ... 36 elided