Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update example plugin #1061

Merged
merged 2 commits into from Jan 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
53 changes: 37 additions & 16 deletions examples/connector_templates/README.md
@@ -1,16 +1,37 @@
# Using templates to implement Secretless Connector Plugins

We created connector templates to ease the process of adding new connectors to secretless.
Before using the templates to add new connector plugins, be sure to read the [Secretless Connector Plugins README](https://github.com/cyberark/secretless-broker/blob/master/pkg/secretless/plugin/connector/README.md)

To add a new connector do the following:

1. Copy the relevant template directory (HTTP/TCP) into `internal/plugin/connectors/<connector type>`.
If you're not sure which connector type is suitable, please refer to the [connector technical overview](https://github.com/cyberark/secretless-broker/tree/master/pkg/secretless/plugin/connector#technical-overview).
1. Inside each template directory you will find the required files & structs implemented,
with instructions in the form of TODOs to fill them with the content of the new connector.
1. Add an entry to the `Plugins` map defined in GetInternalPluginsFunc() of
[`internal_plugins.go`](../../pkg/secretless/plugin/sharedobj/internal_plugins.go), according to their type (HTTP/TCP)
1. Copy the [`template_connector_test`](template_connector_test) directory into `test/connector/<connector type>/` and rename it to `<connector_name>`.
1. This directory will help you write integration tests for your connector. It contains test scripts & files to help you stand up networked containers with docker-compose. The files give instructions on the steps to set up your test suite in the form of TODOs.
The [`Jenkinsfile`](../../Jenkinsfile) is set up to automatically run the integration tests with each project build.
# Using templates to create Secretless Connector Plugins

We created the templates in this directory to make it easier to add new
connectors to Secretless.

Before using the templates, be sure to read the [Secretless Connector Plugins
README](https://github.com/cyberark/secretless-broker/blob/master/pkg/secretless/plugin/connector/README.md)

To create a new Secretless connector plugin, follow these instructions:

1. Copy the relevant template directory (HTTP/TCP) into a folder on your local
machine (or to `internal/plugin/connectors/<connector_type>` if you are building
an internal connector).

If you're not sure which connector type is appropriate for your target service,
please refer to the [connector technical overview](https://github.com/cyberark/secretless-broker/tree/master/pkg/secretless/plugin/connector#technical-overview) for guidelines.

1. Update the copied files to implement your connector. Each file includes
instructions in the form of `TODO`s.

1. (**Internal Connectors Only**) Add an entry to the `Plugins` map defined in
`GetInternalPluginsFunc()` of
[`internal_plugins.go`](../../pkg/secretless/plugin/sharedobj/internal_plugins.go),
according to your connector type (HTTP/TCP)

1. To test your connector, copy the [`template_connector_test`](template_connector_test)
directory onto your local machine.

If you follow the `TODO`-based instructions included in the files in this directory,
you will be able to write integration tests for your connector using `docker-compose`.
The included test scripts & files will help you stand up networked containers with
`docker-compose`.

**Note for internal connectors:** The the test directory should be copied
into `test/connector/<connector type>/` and renamed to `<connector_name>`.
The [`Jenkinsfile`](../../Jenkinsfile) is set up to automatically run the
integration tests from this directory with each project build.
4 changes: 3 additions & 1 deletion examples/connector_templates/http/template/connector.go
@@ -1,4 +1,6 @@
package template
package main

// TODO: change the package name to your plugin name if this will be an internal connector

import (
gohttp "net/http"
Expand Down
4 changes: 3 additions & 1 deletion examples/connector_templates/http/template/plugin.go
@@ -1,4 +1,6 @@
package template
package main

// TODO: change the package name to your plugin name if this will be an internal connector

import (
"github.com/cyberark/secretless-broker/pkg/secretless/plugin/connector"
Expand Down
4 changes: 3 additions & 1 deletion examples/connector_templates/tcp/template/connector.go
@@ -1,4 +1,6 @@
package template
package main

// TODO: change the package name to your plugin name if this will be an internal connector

import (
"net"
Expand Down
4 changes: 3 additions & 1 deletion examples/connector_templates/tcp/template/plugin.go
@@ -1,4 +1,6 @@
package template
package main

// TODO: change the package name to your plugin name if this will be an internal connector

import (
"net"
Expand Down
Expand Up @@ -3,6 +3,9 @@ version: '3.0'
services:
# TODO: add a service for the platform you want secretless to connect with

# TODO: make sure Secretless runs with your plugin
# which may mean adding the `.so` file as a volume
# and revising the command to pass in the `.so` using the `-p` flag
secretless:
image: secretless-broker # this image is built by bin/build
volumes:
Expand Down
2 changes: 1 addition & 1 deletion test/plugin/Dockerfile
Expand Up @@ -7,7 +7,7 @@ COPY . .
RUN mkdir -p /usr/local/lib/secretless && \
go build -buildmode=plugin \
-o /usr/local/lib/secretless/example-plugin.so \
./example/example_plugin.go
./example/
sgnn7 marked this conversation as resolved.
Show resolved Hide resolved

# Do not remove this - we are intentionally trying to exercise
# limited user functionality
Expand Down
70 changes: 70 additions & 0 deletions test/plugin/example/connector.go
@@ -0,0 +1,70 @@
package main

import (
"bufio"
"fmt"
"net"

"github.com/cyberark/secretless-broker/pkg/secretless/log"
"github.com/cyberark/secretless-broker/pkg/secretless/plugin/connector"
)

// SingleUseConnector creates an authenticated connection to a target TCP service.
type SingleUseConnector struct {
logger log.Logger
}

// Connect is the function that implements the tcp.Connector func signature in this
// example plugin. It has access to the client connection and the credentials (as a map),
// and is expected to return the target service connection.
//
// This example connector works as follows:
// 1. Waits for the initial message from the client
// 2. Connect to a target service whose address is the value of the credential identified
// by the key "address"
// 3. Inject credentials from a credential identified by the key "auth"
// 4. Write the initial message from the client with some modification
func (connector *SingleUseConnector) Connect(
clientConn net.Conn,
credentialValuesByID connector.CredentialValuesByID,
) (net.Conn, error) {

connector.logger.Debugln("Waiting for initial write from client")
clientInitMsg, _, err := bufio.NewReader(clientConn).ReadLine()
if err != nil {
return nil, err
}

connector.logger.Debugln("Dialing target service")
conn, err := net.Dial("tcp", string(credentialValuesByID["address"]))
if err != nil {
return nil, err
}

connector.logger.Debugln("Sending packet with injected credentials to target service")
credInjectionPacket := []byte(
fmt.Sprintf(
"credential injection: %s\n",
string(credentialValuesByID["auth"]),
),
)
_, err = conn.Write(credInjectionPacket)
if err != nil {
return nil, err
}

connector.logger.Debugln("Sending modified client initial packet to target service")
initMsgPacket := []byte(
fmt.Sprintf(
"initial message from client: %s\n",
string(clientInitMsg),
),
)
_, err = conn.Write(initMsgPacket)
if err != nil {
return nil, err
}

connector.logger.Debugln("Successfully connected to target service")
return conn, nil
}
109 changes: 0 additions & 109 deletions test/plugin/example/example_plugin.go

This file was deleted.

47 changes: 47 additions & 0 deletions test/plugin/example/plugin.go
@@ -0,0 +1,47 @@
package main

import (
"net"

"github.com/cyberark/secretless-broker/pkg/secretless/plugin/connector"
"github.com/cyberark/secretless-broker/pkg/secretless/plugin/connector/tcp"
)

// NewConnector is a required method on the tcp.Plugin interface. It returns a
// tcp.Connector.
//
// The single argument passed in is of type connector.Resources. It contains
// connector-specific config and a logger.
func NewConnector(conRes connector.Resources) tcp.Connector {
connectorFunc := func(
clientConn net.Conn,
credentialValuesByID connector.CredentialValuesByID,
) (backendConn net.Conn, err error) {
// singleUseConnector is responsible for generating the authenticated connection
// to the target service for each incoming client connection
singleUseConnector := &SingleUseConnector{
logger: conRes.Logger(),
}

return singleUseConnector.Connect(clientConn, credentialValuesByID)
}

return tcp.ConnectorFunc(connectorFunc)
}

// PluginInfo is required as part of the Secretless plugin spec. It provides
// important metadata about the plugin.
func PluginInfo() map[string]string {
return map[string]string{
"pluginAPIVersion": "0.1.0",
"type": "connector.tcp",
"id": "example-tcp-connector",
"description": "Example TCP Connector Plugin",
}
}

// GetTCPPlugin is required as part of the Secretless plugin spec for TCP connector
// plugins. It returns the TCP plugin.
func GetTCPPlugin() tcp.Plugin {
return tcp.ConnectorConstructor(NewConnector)
}