A custom plugin for running Open Policy Agent (OPA) in AWS Lambda as a Lambda Extension.
To learn more about how Lambda Extensions work, check out these AWS docs, which provide a helpful graphic depicting the Lambda lifecycle.
This project provides an OPA plugin that integrates OPA with the Lambda Extension API. To use this plugin, you must compile a custom version of the OPA binary. Instructions to do this are available in OPA's documentation. In the future, we hope to contribute/release changes that provide a simpler experience, similar to the opa-envoy-plugin project.
This plugin can be tricky to implement, depending on whether or not you use the OPA discovery plugin.
If you don't need to use the discovery plugin, then you don't need to make many changes in your custom OPA compilation. Just modify main.go to import the plugin module (see snippet just below). If you're unfamiliar with custom plugins in OPA, check out the OPA docs on the subject.
// Copyright 2016 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
package main
import (
"fmt"
"os"
// Import the plugin so that it can register itself with the OPA runtime on init
_ "github.com/godaddy/opa-lambda-extension-plugin/plugins/lambda"
"github.com/open-policy-agent/opa/cmd"
)
func main() {
if err := cmd.RootCommand.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
// Capabilities file generation:
//go:generate build/gen-run-go.sh internal/cmd/genopacapabilities/main.go capabilities.json
// WASM base binary generation:
//go:generate build/gen-run-go.sh internal/cmd/genopawasm/main.go -o internal/compiler/wasm/opa/opa.go internal/compiler/wasm/opa/opa.wasm internal/compiler/wasm/opa/callgraph.csv
Everything else can be wired up in OPA configuration. Note the trigger: manual
on the bundles
, decision_logs
, and status
plugins.
services:
acmecorp:
url: https://example.com/control-plane-api/v1
bundles:
authz:
service: acmecorp
resource: bundles/http/example/authz.tar.gz
polling:
trigger: manual
scope: write
decision_logs:
service: acmecorp
reporting:
trigger: manual
status:
service: acmecorp
trigger: manual
plugins:
lambda_extension:
minimum_trigger_threshold: 30
trigger_timeout: 7
plugin_start_priority:
- bundle
- decision_logs
- status
plugin_stop_priority:
- decision_logs
- status
- bundle
The discovery plugin prevents other plugins from being registered in the bootstrap configuration. This prevents the lambda extension plugin from being registered via configuration, because the lambda extension plugin must run before the discovery plugin. To use the lambda extension plugin with discovery, you must compile a custom OPA binary wherein you register the lambda extension plugin directly with the runtime, e.g.
lambdaPluginFactory := lambda.PluginFactory{}
rt.Manager.Register(lambda.Name, lambdaPluginFactory.New(rt.Manager, nil))
This is less than ideal and the complexity involved with this implementation is outside the scope of this document. For now, just know that if you really need to implement both the discovery and lambda extension plugins, it is possible to do so. In the future, we hope to contribute/release changes that make this implementation simpler.
plugins:
lambda_extension:
# The number of seconds that must elapse before plugins will be triggered by a lambda function invocation
minimum_trigger_threshold: 30
# The number of seconds that ALL plugins have to complete their trigger before they are canceled.
trigger_timeout: 7
# The order in which plugins will be started while the Lambda Extension is in its init phase.
plugin_start_priority:
- bundle
- decision_logs
- status
# The order in which plugins will be stopped while the Lambda Extension is in its shutdown phase.
plugin_stop_priority:
- decision_logs
- status
- bundle
make fmt
make lint
make test
The plugin is heavily commented with useful information.