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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ tmp

.kitchen/
.kitchen.local.yml
vendor/bundle/
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ will need access to an [AWS][aws_site] account. [IAM][iam_site] users should hav
By automatically applying reasonable defaults wherever possible, kitchen-ec2 does a lot of work to make your life easier.
See the [kitchen.ci kitchen-ec2 docs](https://kitchen.ci/docs/drivers/aws/) for a complete list of configuration options.

### Transport Options

kitchen-ec2 supports multiple transport methods for connecting to EC2 instances:

- **SSH/WinRM** (default): Traditional network-based access
- **Instance Connect**: AWS EC2 Instance Connect for temporary SSH access
- **SSM Session Manager**: AWS Systems Manager Session Manager for secure, audited access without SSH/RDP ports

For SSM Session Manager configuration and benefits, see [SSM Session Manager Documentation](docs/ssm-session-manager.md).

## Development

* Source hosted at [GitHub][repo]
Expand Down
70 changes: 70 additions & 0 deletions docs/ssm-session-manager.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# AWS SSM Session Manager Support

kitchen-ec2 now supports AWS Systems Manager (SSM) Session Manager as an alternative transport method to SSH/WinRM. This feature enables Test Kitchen to connect to EC2 instances without requiring direct network connectivity or SSH key management.

## Benefits

- **No SSH/WinRM network access required**: Connect to instances in private subnets without VPN or bastion hosts
- **Enhanced security**: No need to open SSH/RDP ports in security groups
- **Centralized audit logging**: All session activity is logged to CloudTrail
- **No SSH key management**: Eliminate the complexity of managing SSH key pairs for testing
- **Zero-trust compliance**: Access instances through AWS IAM authentication instead of network-based access

## Requirements

### Client Requirements

1. **AWS CLI**: Install the AWS CLI version 2.x or later
2. **Session Manager Plugin**: Install the Session Manager plugin for AWS CLI

### Instance Requirements

1. **SSM Agent**: Must be installed and running on the EC2 instance
2. **IAM Instance Profile**: Instance must have the `AmazonSSMManagedInstanceCore` managed policy or equivalent
3. **Network Access**: Outbound HTTPS (port 443) access to AWS SSM endpoints

## Configuration

### Basic Configuration

```yaml
driver:
name: ec2
use_ssm_session_manager: true
iam_profile_name: my-ssm-enabled-profile
```

### Complete Example

```yaml
driver:
name: ec2
use_ssm_session_manager: true
instance_type: t3.micro
subnet_id: subnet-12345678
iam_profile_name: kitchen-ec2-ssm-profile
security_group_ids:
- sg-87654321

platforms:
- name: amazon2
- name: ubuntu-20.04

suites:
- name: default
run_list:
- recipe[my_cookbook::default]
```

## Configuration Options

| Option | Default | Description |
|--------|---------|-------------|
| `use_ssm_session_manager` | `false` | Enable SSM Session Manager transport |
| `ssm_session_manager_document_name` | `nil` | Optional custom SSM document name |
| `iam_profile_name` | `nil` | IAM instance profile (required for SSM) |

## Additional Resources

- [AWS Systems Manager Session Manager Documentation](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager.html)
- [Session Manager Plugin Installation](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html)
1 change: 1 addition & 0 deletions kitchen-ec2.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Gem::Specification.new do |gem|

gem.add_dependency "aws-sdk-ec2", "~> 1.0"
gem.add_dependency "aws-sdk-ec2instanceconnect", "~> 1.0"
gem.add_dependency "aws-sdk-ssm", "~> 1.0"
gem.add_dependency "retryable", ">= 2.0", "< 4.0" # 4.0 will need to be validated
gem.add_dependency "sshkey", "~> 2.0"
gem.add_dependency "test-kitchen", ">= 3.9.0", "< 4"
Expand Down
85 changes: 85 additions & 0 deletions lib/kitchen/driver/aws/ssm_session_manager.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#
# Author:: GitHub Copilot
#
# Copyright:: 2025, GitHub
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require "aws-sdk-ssm"
require "open3"

module Kitchen
module Driver
class Aws
# Manages AWS Systems Manager Session Manager connections for Test Kitchen
class SsmSessionManager
def initialize(config, logger)
@config = config
@logger = logger
@ssm_client = ::Aws::SSM::Client.new(
region: config[:region],
profile: config[:shared_credentials_profile]
)
end

# Check if SSM agent is running on the instance
def ssm_agent_available?(instance_id)
@logger.debug("Checking if SSM agent is available on instance #{instance_id}")

begin
resp = @ssm_client.describe_instance_information(
filters: [
{
key: "InstanceIds",
values: [instance_id],
},
]
)

available = !resp.instance_information_list.empty? &&
resp.instance_information_list.first.ping_status == "Online"

if available
@logger.info("SSM agent is available on instance #{instance_id}")
else
@logger.warn("SSM agent is not available on instance #{instance_id}")
end

available
rescue ::Aws::SSM::Errors::ServiceError => e
@logger.warn("Error checking SSM agent status: #{e.message}")
false
end
end

# Verify that the AWS CLI session manager plugin is installed
def session_manager_plugin_installed?
_output, status = Open3.capture2e("session-manager-plugin", "--version")
installed = status.success?

if installed
@logger.debug("Session Manager plugin is installed")
else
@logger.warn("Session Manager plugin is not installed. Install it from: " \
"https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html")
end

installed
rescue StandardError => e
@logger.warn("Error checking for session-manager-plugin: #{e.message}")
false
end
end
end
end
end
Loading