Skip to content

Cluster Access

Acccessing the cluster

Some Flight implementations may require generating random data, which is useful for tasks like creating initial passwords or generating cryptographic certificates. However, this approach has a drawback: the inability to reproduce the same values across runs. This can lead to unnecessary churn when deploying updated releases.

One of the key advantages of using WebAssembly (Wasm) is its secure sandboxing, which ensures package implementations run in isolation without direct access to external systems. Since Wasm is merely an assembly instruction set, it can only perform numeric computations by itself.

To extend Wasm’s capabilities, we use the WebAssembly System Interface (WASI), which allows external calls from the WebAssembly module to the host. Yoke leverages WASI to expose a single function: k8s_lookup.

This function enables Flights to look up Kubernetes resources, but only those owned by the target release. This allows packages to reuse values from previous iterations, reducing unnecessary churn, rollouts, and downtime during updates.

This feature is opt-in during takeoff:

Terminal window
yoke takeoff --cluster-access foo bar.wasm

A Note on Security

Security-conscious users may wonder whether granting Flights access to the cluster introduces a vulnerability. However, Wasm modules do not have direct access to the cluster. Instead, they interact with the host Yoke program, which retrieves the requested resource and returns its JSON representation to the module’s memory. The Wasm module itself cannot open sockets, file descriptors, or network connections.

That said, this feature remains opt-in and is recommended for use only with trusted Flights.

Example Usage

The k8s_lookup function is a low-level host export, and users are not expected to call it directly. Instead, Yoke provides a Go package that wraps it in a more user-friendly API: github.com/yokecd/yoke/pkg/flight/wasi/k8s.

For other languages, contributors are welcome to reference the implementation or request official support for their preferred ecosystem.

A Go-based example can be found here.


example.go
package main
import (
"crypto/rand"
"encoding/json"
"fmt"
"os"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/yokecd/yoke/pkg/flight"
"github.com/yokecd/yoke/pkg/flight/wasi/k8s"
)
func main() {
if err := run(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func run() error {
secretName := flight.Release() + "-example"
secret, err := k8s.Lookup[corev1.Secret](k8s.ResourceIdentifier{
ApiVersion: "v1",
Kind: "Secret",
Name: secretName,
Namespace: flight.Namespace(),
})
if err != nil && !k8s.IsErrNotFound(err) {
return fmt.Errorf("failed to lookup secret: %v", err)
}
return json.NewEncoder(os.Stdout).Encode(corev1.Secret{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "Secret",
},
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
},
StringData: map[string]string{
"password": func() string {
if secret != nil {
// if the secret already exists we want to reuse the example value instead of generating a new random string.
return string(secret.Data["password"])
}
// Since the secret does not exist we need to generate a new password via the power of entropy!
return RandomString()
}(),
},
})
}
func RandomString() string {
buf := make([]byte, 6)
rand.Read(buf)
return fmt.Sprintf("%x", buf)
}