Skip to content

Commit 18aac3d

Browse files
committed
Initial Commit
1 parent 3c0e607 commit 18aac3d

File tree

11 files changed

+656
-2
lines changed

11 files changed

+656
-2
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/build/
2+
.idea
3+
.gradle

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@
186186
same "printed page" as the copyright notice for easier
187187
identification within third-party archives.
188188

189-
Copyright [yyyy] [name of copyright owner]
189+
Copyright [2024] [Ed Kingscote]
190190

191191
Licensed under the Apache License, Version 2.0 (the "License");
192192
you may not use this file except in compliance with the License.

README.md

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,83 @@
1-
# rundeck-plugin-aws-ec2-ice-node-execution
1+
# AWS EC2 Instance Connect Endpoint Node Execution Plugin for Rundeck
2+
3+
This plugin provides node executor and file-copier support to AWS EC2 via the Instance Connect Endpoint.
4+
Use this plugin if you must access servers via AWS EC2 Instance Connect Endpoint.
5+
6+
It is based upon the openssh Bastion Node Execution Plugin, and shares similar characteristics. This should make it easier to extend/tweak for more AWS parameters in the future if required.
7+
8+
The AWS CLI v2 must be installed and available to Rundeck.
9+
10+
## Dry run mode
11+
You can configure the plugin to just print the invocation string to the console.
12+
This can be useful when defining the configuration properties.
13+
14+
## Plugin Configuration Properties
15+
* AWS Access Key
16+
* AWS Secret Key - set to storage path location in Rundeck Keystore
17+
* AWS Default Region
18+
* Node SSH Key - set to storage path location in Rundeck Keystore
19+
* SSH Options: Extra options to pass to the ssh command invocation.
20+
* Template ssh_config: Customize ProxyCommand and other flags. Consult the reference for [ssh_config(5)](https://linux.die.net/man/5/ssh_config) to learn about posible settings.
21+
* Dry run? If set true, just print the command invocation that would be used but do not execute the command. This is useful to preview.
22+
23+
## Node Specific Configuration Attributes
24+
25+
* `ssh-key-storage-path` SSH key override - from the Rundeck Keystore.
26+
* `ssh-ssh-config` - SSH extra options override
27+
* `ssh-scp-config` - File Copier extra options override
28+
29+
## Configuration
30+
31+
The plugin can be configured as a default node executor and file copier for a Project. Use the Simple Conguration tab to see the configuration properties. The page has a form with inputs to configure the connection
32+
33+
You can also modify the project.properties or use the API/CLI to define the plugin configuration.
34+
35+
The Plugin List page will describe the key names to set.
36+
37+
#### Customize the ssh_config
38+
39+
You can define multiple lines using a trailing backslash and an indent on the following line.
40+
41+
Here is an example that defines ssh_config file.
42+
43+
project.plugin.NodeExecutor.openssh-bastion-host.node-executor.ssh_config=Host i-* \
44+
StrictHostKeyChecking no
45+
Port 22
46+
ProxyCommand aws ec2-instance-connect open-tunnel --instance-id @instance_id@
47+
IdentityFile @plugin.config.identity_file@
48+
49+
Here ssh_options are set.
50+
51+
project.plugin.NodeExecutor.openssh-bastion-host.node-executor.ssh_options="-q -oCiphers=arcfour -oClearAllForwardings=yes"
52+
53+
Using Dry run, you might see output similar to this:
54+
55+
[dry-run] +------------------------------------------+
56+
[dry-run] | ssh_config |
57+
[dry-run] +------------------------------------------+
58+
[dry-run] | Host i- *
59+
[dry-run] | StrictHostKeyChecking no
60+
[dry-run] | Port 22
61+
[dry-run] | ProxyCommand aws ec2-instance-connect open-tunnel --instance-id i-123455678a01bcdefa
62+
[dry-run] | IdentityFile /tmp/bastion.ssh-keyfile.prWLUyFU
63+
[dry-run] +------------------------------------------+
64+
[dry-run] ssh -q -oCiphers=arcfour -oClearAllForwardings=yes -F /tmp/ssh_config.zTr9j5KK -i /tmp/host1234.ssh-keyfile.4cjnI2qL ec2user@i-123455678a01bcdefa whoami
65+
Begin copy 18 bytes to node host1234: /etc/motd -> /tmp/motd
66+
[dry-run] +------------------------------------------+
67+
[dry-run] | ssh_config |
68+
[dry-run] +------------------------------------------+
69+
[dry-run] | Host *
70+
[dry-run] | StrictHostKeyChecking no
71+
[dry-run] | Port 22
72+
[dry-run] | ProxyCommand aws ec2-instance-connect open-tunnel --instance-id i-123455678a01bcdefa
73+
[dry-run] | IdentityFile /tmp/bastion.ssh-keyfile.XXXXX.WAlpZLNb
74+
[dry-run] |
75+
[dry-run] +------------------------------------------+
76+
[dry-run] scp -q -oCiphers=arcfour -oClearAllForwardings=yes -F /tmp/ssh_config.XXXX.cosJ7xQ2 -i /tmp/host1234.ssh-keyfile.XXXXX.BOqYAKRu /etc/motd ec2-user@i-123455678a01bcdefa:/tmp/motd
77+
/tmp/motd
78+
Copied: /tmp/motd
79+
80+
## Docker
81+
82+
An example Dockerfile is provided to install the AWS CLI v2 on the latest base Rundeck container from Dockerhub.
83+

build.gradle

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
buildscript {
2+
repositories {
3+
mavenCentral()
4+
}
5+
}
6+
plugins {
7+
id 'pl.allegro.tech.build.axion-release' version '1.11.0'
8+
}
9+
10+
ext.pluginName = 'AWS EC2 ICE"
11+
ext.pluginDescription = "AWS EC2 Instance Connect Endpoint Node Executor"
12+
ext.sopsCopyright = "© 2024, Ed Kingscote"
13+
ext.sopsUrl = "http://rundeck.com"
14+
ext.buildDateString=new Date().format("yyyy-MM-dd'T'HH:mm:ssX")
15+
ext.archivesBaseName = "aws-ec2-ice-node-execution"
16+
ext.pluginBaseFolder = "."
17+
18+
scmVersion {
19+
ignoreUncommittedChanges = true
20+
tag {
21+
prefix = ''
22+
versionSeparator = ''
23+
def origDeserialize=deserialize
24+
//apend .0 to satisfy semver if the tag version is only X.Y
25+
deserialize = { config, position, tagName ->
26+
def orig = origDeserialize(config, position, tagName)
27+
if (orig.split('\\.').length < 3) {
28+
orig += ".0"
29+
}
30+
orig
31+
}
32+
}
33+
}
34+
35+
project.version = scmVersion.version
36+
ext.archiveFilename = ext.archivesBaseName + '-' + version
37+
38+
apply from: 'https://raw.githubusercontent.com/rundeck-plugins/build-zip/master/build.gradle'

contents/file-copier

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# scp -o ProxyCommand='aws ec2-instance-connect open-tunnel --instance-id i-02940408e08ececbf' testfile kingscoe@i-02940408e08ececbf:testfile
2+
#!/usr/bin/env bash
3+
4+
set -eu
5+
6+
scp() {
7+
if [[ "${RD_CONFIG_DRY_RUN:-}" == "true" ]]
8+
then
9+
10+
echo >&2 "[dry-run] +------------------------------------------+"
11+
echo >&2 "[dry-run] | ssh_config |"
12+
echo >&2 "[dry-run] +------------------------------------------+"
13+
while IFS= read -r line; do
14+
echo >&2 "[dry-run] | $line"
15+
done < "$SSH_CONFIG_FILE"
16+
echo >&2 "[dry-run] +------------------------------------------+"
17+
echo >&2 "[dry-run] scp $*"
18+
else
19+
command scp "$@"
20+
fi
21+
}
22+
23+
FILE_SOURCE=$1
24+
FILE_DESTINATION=$2
25+
26+
SSH_CONFIG_FILE_TMP=$(mktemp -t "ssh_config.XXXX")
27+
SSH_CONFIG_FILE=$(mktemp -t "ssh_config.XXXX")
28+
SSH_NODE_KEY_FILE=$(mktemp -t "$RD_NODE_NAME.ssh-keyfile.XXXXX")
29+
trap 'rm "$SSH_CONFIG_FILE_TMP" "$SSH_CONFIG_FILE" "$SSH_NODE_KEY_FILE"' EXIT
30+
31+
if [[ -n "${RD_CONFIG_SSH_KEY_STORAGE_PATH:-}" ]]
32+
then
33+
echo "$RD_CONFIG_SSH_KEY_STORAGE_PATH" > "$SSH_NODE_KEY_FILE"
34+
NODE_IDENTITY_FILE="$SSH_NODE_KEY_FILE"
35+
fi
36+
37+
echo "$RD_CONFIG_SSH_CONFIG" > "$SSH_CONFIG_FILE_TMP"
38+
sed -e "s#@instance_id@#$RD_NODE_HOSTNAME#g" < "$SSH_CONFIG_FILE_TMP" > "$SSH_CONFIG_FILE"
39+
40+
SSH_ARGS=($RD_CONFIG_SSH_OPTS -F "$SSH_CONFIG_FILE")
41+
[[ -n "${NODE_IDENTITY_FILE:-}" ]] && SSH_ARGS=(${SSH_ARGS[@]} -i "$NODE_IDENTITY_FILE")
42+
43+
export AWS_ACCESS_KEY_ID=$RD_CONFIG_AWS_ACCESS_KEY_ID
44+
export AWS_SECRET_ACCESS_KEY=$RD_CONFIG_AWS_SECRET_ACCESS_KEY_STORAGE_PATH
45+
export AWS_DEFAULT_REGION=$RD_CONFIG_AWS_DEFAULT_REGION
46+
47+
scp "${SSH_ARGS[@]}" \
48+
"$FILE_SOURCE" \
49+
"${RD_NODE_USERNAME}@${RD_NODE_HOSTNAME}:${FILE_DESTINATION}"
50+
51+
echo "$FILE_DESTINATION"
52+
53+
exit $?

contents/node-executor

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#!/usr/bin/env bash
2+
3+
set -eu
4+
5+
ssh() {
6+
if [[ "${RD_CONFIG_DRY_RUN:-}" == "true" ]]
7+
then
8+
9+
echo >&2 "[dry-run] +------------------------------------------+"
10+
echo >&2 "[dry-run] | ssh_config |"
11+
echo >&2 "[dry-run] +------------------------------------------+"
12+
while IFS= read -r line; do
13+
echo >&2 "[dry-run] | $line"
14+
done < "$SSH_CONFIG_FILE"
15+
echo >&2 "[dry-run] +------------------------------------------+"
16+
echo >&2 "[dry-run] ssh $*"
17+
else
18+
command ssh "$@"
19+
fi
20+
}
21+
22+
SSH_CONFIG_FILE_TMP=$(mktemp -t "ssh_config.XXXX")
23+
SSH_CONFIG_FILE=$(mktemp -t "ssh_config.XXXX")
24+
SSH_NODE_KEY_FILE=$(mktemp -t "$RD_NODE_NAME.ssh-keyfile.XXXXX")
25+
trap 'rm "$SSH_CONFIG_FILE_TMP" "$SSH_CONFIG_FILE" "$SSH_NODE_KEY_FILE"' EXIT
26+
27+
if [[ -n "${RD_CONFIG_SSH_KEY_STORAGE_PATH:-}" ]]
28+
then
29+
echo "$RD_CONFIG_SSH_KEY_STORAGE_PATH" > "$SSH_NODE_KEY_FILE"
30+
NODE_IDENTITY_FILE="$SSH_NODE_KEY_FILE"
31+
fi
32+
33+
echo "$RD_CONFIG_SSH_CONFIG" > "$SSH_CONFIG_FILE_TMP"
34+
sed -e "s#@instance_id@#$RD_NODE_HOSTNAME#g" < "$SSH_CONFIG_FILE_TMP" > "$SSH_CONFIG_FILE"
35+
36+
SSH_ARGS=($RD_CONFIG_SSH_OPTS -F "$SSH_CONFIG_FILE")
37+
[[ -n "${NODE_IDENTITY_FILE:-}" ]] && SSH_ARGS=(${SSH_ARGS[@]} -i "$NODE_IDENTITY_FILE")
38+
39+
export AWS_ACCESS_KEY_ID=$RD_CONFIG_AWS_ACCESS_KEY_ID
40+
export AWS_SECRET_ACCESS_KEY=$RD_CONFIG_AWS_SECRET_ACCESS_KEY_STORAGE_PATH
41+
export AWS_DEFAULT_REGION=$RD_CONFIG_AWS_DEFAULT_REGION
42+
43+
ssh "${SSH_ARGS[@]}" \
44+
"${RD_NODE_USERNAME}@${RD_NODE_HOSTNAME}" \
45+
"$@"
46+
47+
exit $?

gradle/wrapper/gradle-wrapper.jar

53.1 KB
Binary file not shown.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
distributionBase=GRADLE_USER_HOME
2+
distributionPath=wrapper/dists
3+
zipStoreBase=GRADLE_USER_HOME
4+
zipStorePath=wrapper/dists
5+
distributionUrl=https\://services.gradle.org/distributions/gradle-4.5.1-bin.zip

0 commit comments

Comments
 (0)