Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions cmd/plugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package cmd

import (
"github.com/spf13/cobra"
)

func newPluginCmd() *cobra.Command {
pluginCmd := &cobra.Command{
Use: "plugin",

Check failure on line 9 in cmd/plugin.go

View workflow job for this annotation

GitHub Actions / lint

File is not properly formatted (gci)
Short: "Manage and validate Kong plugins",
Long: `The plugin command set allows you to manage, validate, and lint Kong plugins locally.`,
}

pluginCmd.AddCommand(newPluginLintCmd())


return pluginCmd
}
100 changes: 100 additions & 0 deletions cmd/plugin_lint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package cmd

import (
"errors"
"fmt"
"io"
"os"
"strings"

"github.com/kong/deck/plugin/lua"
"github.com/spf13/cobra"

Check failure on line 12 in cmd/plugin_lint.go

View workflow job for this annotation

GitHub Actions / lint

File is not properly formatted (gci)
)

var (
pluginLintCode string
pluginLintEdition string
pluginLintSandbox string
)

// Executes plugin lint command.
func executePluginLint(cmd *cobra.Command, args []string) error{

Check failure on line 22 in cmd/plugin_lint.go

View workflow job for this annotation

GitHub Actions / lint

unused-parameter: parameter 'cmd' seems to be unused, consider removing or renaming it as _ (revive)
var luaCode string
var err error

if pluginLintCode == "-" {
luaCode, err = readFromStdin()
} else {
content, readErr := os.ReadFile(pluginLintCode)
if readErr != nil {
return fmt.Errorf("failed to read file %s: %w", pluginLintCode, readErr)
}
luaCode = string(content)

}

if err != nil {
return fmt.Errorf("failed to read input: %w", err)
}

if strings.TrimSpace(luaCode) == "" {
return errors.New("no Lua code provided. Use --code or pipe code to stdin")
}


v, err := lua.NewValidator(pluginLintEdition, "")
if err != nil {
return err
}

violations, err := v.Validate(luaCode, pluginLintSandbox)
if err != nil {
return err
}

if len(violations) == 0 {
fmt.Println("Success: No violations found. Your Lua code is safe for the specified sandbox.")
return nil
}

fmt.Printf("Found %d violations:\n", len(violations))
for _, vio := range violations {
lineInfo := ""
if vio.Line > 0 {
lineInfo = fmt.Sprintf(" (line %d)", vio.Line)
}
fmt.Printf(" - [%s] %s: %s%s\n", vio.Severity, vio.ID, vio.Message, lineInfo)
}


return errors.New("lua validation failed")

Check failure on line 72 in cmd/plugin_lint.go

View workflow job for this annotation

GitHub Actions / lint

File is not properly formatted (gofumpt)


}
func readFromStdin() (string, error) {
data, err := io.ReadAll(os.Stdin)
if err != nil {
return "", fmt.Errorf("error reading from stdin: %w", err)
}

return string(data), err
}


func newPluginLintCmd() *cobra.Command {
pluginLintCmd := &cobra.Command{
Use: "lint [flags]",
Short: "Check custom LUA code for security and sandbox compatibility",
RunE: func(cmd *cobra.Command, args []string) error {
return executePluginLint(cmd, args)
},
}

pluginLintCmd.Flags().StringVarP(&pluginLintCode, "code", "c", "-", "custom LUA code to validate. Use - to read from stdin.")

Check failure on line 95 in cmd/plugin_lint.go

View workflow job for this annotation

GitHub Actions / lint

The line is 126 characters long, which exceeds the maximum of 120 characters. (lll)
pluginLintCmd.Flags().StringVarP(&pluginLintEdition, "edition", "e", "ee", "Kong Edition [choices: ee (enterprise), oss (open source).")

Check failure on line 96 in cmd/plugin_lint.go

View workflow job for this annotation

GitHub Actions / lint

The line is 137 characters long, which exceeds the maximum of 120 characters. (lll)
pluginLintCmd.Flags().StringVarP(&pluginLintSandbox, "sandbox", "s", "strict", "Kong Edition [choices: ee (enterprise), oss (open source).")

Check failure on line 97 in cmd/plugin_lint.go

View workflow job for this annotation

GitHub Actions / lint

The line is 141 characters long, which exceeds the maximum of 120 characters. (lll)

return pluginLintCmd
}
5 changes: 5 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,9 @@ It can be used to export, import, or sync entities to Kong.`,
rootCmd.AddCommand(newDiffCmd(true)) // deprecated, to exist under the `gateway` subcommand only
rootCmd.AddCommand(newConvertCmd(true)) // deprecated, to exist under the `file` subcommand only
rootCmd.AddCommand(newKonnectCmd()) // deprecated, to be removed

rootCmd.AddCommand(newPluginCmd())

{
gatewayCmd := newGatewaySubCmd()
rootCmd.AddCommand(gatewayCmd)
Expand Down Expand Up @@ -267,6 +270,8 @@ It can be used to export, import, or sync entities to Kong.`,
fileCmd.AddCommand(newKong2KicCmd())
fileCmd.AddCommand(newKong2TfCmd())
}


return rootCmd
}

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ require (
github.com/xlab/treeprint v1.2.0 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
github.com/yuin/goldmark v1.8.2 // indirect
github.com/yuin/gopher-lua v1.1.2 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect
go.opentelemetry.io/otel v1.33.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,8 @@ github.com/yuin/goldmark v1.8.2 h1:kEGpgqJXdgbkhcOgBxkC0X0PmoPG1ZyoZ117rDVp4zE=
github.com/yuin/goldmark v1.8.2/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
github.com/yuin/gopher-lua v1.1.2 h1:yF/FjE3hD65tBbt0VXLE13HWS9h34fdzJmrWRXwobGA=
github.com/yuin/gopher-lua v1.1.2/go.mod h1:7aRmXIWl37SqRf0koeyylBEzJ+aPt8A+mmkQ4f1ntR8=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
Expand Down
104 changes: 104 additions & 0 deletions pkg/lua/policies/kong_ee_3x.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Kong Enterprise Lua Sandbox Knowledge Base
# Accurate mapping from kong/tools/sandbox/environment/

version: "1.0"
edition: "EE"

profiles:
- name: lua
description: "Base Lua environment. Standard libraries only."
allowed_globals:
- _VERSION
- assert
- error
- ipairs
- next
- pairs
- pcall
- print
- select
- tonumber
- tostring
- type
- unpack
- xpcall
allowed_prefixes:
- bit.
- coroutine.
- io.type
- jit.
- math.
- os.clock
- os.date
- os.difftime
- os.time
- string.
- table.

- name: strict
extends: lua
description: "Standard Kong Sandbox. Safe PDK and Nginx utilities."
allowed_globals:
- kong
- ngx
allowed_prefixes:
- kong.client.
- kong.cluster.
- kong.default_workspace
- kong.ip.
- kong.jwe.
- kong.nginx.
- kong.node.
- kong.plugin.
- kong.request.
- kong.response.
- kong.service.request.
- kong.service.response.
- kong.table.
- kong.telemetry.
- kong.tracing.
- kong.version
- ngx.log
- ngx.sleep
- ngx.time
- ngx.re.
- ngx.req.
- ngx.resp.
- ngx.worker.
- ngx.config.
# Common constants
- ngx.HTTP_
- ngx.OK
- ngx.ERR
- ngx.INFO

- name: lax
extends: strict
description: "Permissive Sandbox. Allows DB, cache, and network sockets."
allowed_prefixes:
- kong.cache.
- kong.db.consumers.
- kong.db.services.
- kong.db.routes.
- kong.db.upstreams.
- kong.db.targets.
- kong.db.plugins.
- kong.db.certificates.
- kong.db.snis.
- kong.db.ca_certificates.
- kong.dns.
- kong.vault.
- ngx.socket.
- ngx.thread.
- ngx.location.capture


rules:
- id: LUA-EV-001
pattern: "(_G\\[|getfenv|setfenv)"
severity: CRITICAL
message: "Potential sandbox evasion: global environment manipulation."
- id: LUA-SEC-001
pattern: "require\\s*\\(['\"] (ffi|os|io) ['\"]\\)"
severity: CRITICAL
message: "Forbidden module loading."
54 changes: 54 additions & 0 deletions pkg/lua/policies/kong_oss_3x.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Kong OSS Lua Sandbox Knowledge Base

version: "1.0"
edition: "OSS"

profiles:
- name: lua
description: "Base Lua environment for OSS"
allowed_globals:
- _VERSION
- assert
- error
- ipairs
- next
- pairs
- pcall
- print
- select
- tonumber
- tostring
- type
- unpack
- xpcall
allowed_prefixes:
- math.
- string.
- table.

- name: standard
extends: lua
description: "Standard OSS Sandbox. Core PDK only."
allowed_globals:
- kong
- ngx
allowed_prefixes:
- kong.log.
- kong.request.
- kong.response.
- kong.service.
- kong.ip.
- kong.table.
- ngx.log
- ngx.sleep
- ngx.time
- ngx.re.
- ngx.exit
- ngx.HTTP_
- ngx.OK

rules:
- id: LUA-EV-001
pattern: "(_G\\[|getfenv|setfenv)"
severity: CRITICAL
message: "Sandbox evasion: global environment access is strictly blocked."
Loading
Loading