-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
169 lines (132 loc) · 4.16 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package main
import (
"errors"
"fmt"
"io"
"log"
"os"
"github.com/ivoronin/ec2ssh/awsutil"
"github.com/ivoronin/ec2ssh/wscat"
)
func FatalError(err error) {
fmt.Fprintf(os.Stderr, "ec2ssh: %v\n", err)
os.Exit(1)
}
var DebugLogger = log.New(io.Discard, "DEBUG: ", log.Ldate|log.Ltime|log.Lshortfile)
const helpText = `Usage: ec2ssh [ec2ssh options] [ssh arguments] destination [command [argument ...]]
Connect to an EC2 instance directly using SSH or via the EC2 Instance Connect
Endpoint (EICE), by the instance ID, private, public, or IPv6 address, private
DNS name, or name tag, using ephemeral SSH keys.
Example - Connect to an instance using the instance ID:
$ ec2ssh -l ec2-user i-0123456789abcdef0
Example - Connect to an instance using a name tag with the public IP address:
$ ec2ssh -p 2222 --address-type public ec2-user@app01
Example - Connect to an instance using its private DNS name via an EICE tunnel:
$ ec2ssh --use-eice ip-10-0-0-1
Example - Use any SSH options and arguments as usual:
$ ec2ssh --use-eice -L 8888:127.0.0.1:8888 -N -i ~/.ssh/id_rsa_alt -o VisualHostKey=Yes app01
Options:
--region <string>
Use the specified AWS region (env AWS_REGION, AWS_DEFAULT_REGION).
Defaults to using the AWS SDK configuration.
--profile <string>
Use the specified AWS profile (env AWS_PROFILE).
Defaults to using the AWS SDK configuration.
--list
List instances in the region and exit.
--list-columns <columns>
Specify columns to display in the list output.
Defaults to ID,NAME,STATE,PRIVATE-IP,PUBLIC-IP
Available columns: ID,NAME,STATE,TYPE,PRIVATE-IP,PUBLIC-IP,IPV6,PRIVATE-DNS,PUBLIC-DNS
--use-eice
Use EC2 Instance Connect Endpoint (EICE) to connect to the instance.
Default is false. Ignores --address-type, private address is always used.
--eice-id <string>
Specifies the EC2 Instance Connect Endpoint (EICE) ID to use.
Defaults to autodetection based on the instance's VPC and subnet.
Automatically implies --use-eice.
--destination-type <id|private_ip|public_ip|ipv6|private_dns|name_tag>
Specify the destination type for instance search.
Defaults to automatically detecting the type based on the destination.
First matched instance will be used for connection.
--address-type <private|public|ipv6>
Specify the address type for connecting to the instance.
Defaults to use the first available address from the list: private, public, ipv6.
--no-send-keys
Do not send SSH keys to the instance using EC2 Instance Connect.
--debug
Enable debug logging.
ssh arguments
Specify arguments to pass to SSH.
destination
Specify the destination for connection. Can be one of: instance ID,
private, public or IPv6 IP address, private DNS name, or name tag.
`
func Usage(err error) {
if err != nil {
fmt.Fprintf(os.Stderr, "ec2ssh: %v\n", err)
}
fmt.Fprint(os.Stderr, helpText)
os.Exit(1)
}
func EnableDebug() {
DebugLogger.SetOutput(os.Stderr)
}
func Run(args []string) error {
parsedArgs, err := ParseArgs(args)
if err != nil {
return err
}
options, err := NewOptions(parsedArgs)
if err != nil {
return err
}
if options.Debug {
EnableDebug()
awsutil.EnableDebug()
}
if err := awsutil.Init(options.Region, options.Profile); err != nil {
return err
}
if options.DoList {
return List(options)
}
if options.Destination == "" {
return fmt.Errorf("%w: missing destination", ErrArgParse)
}
tmpDir, err := os.MkdirTemp("", "ec2ssh")
if err != nil {
return err
}
defer os.RemoveAll(tmpDir)
session, err := NewSession(options, tmpDir)
if err != nil {
return err
}
if err = session.Run(); err != nil {
return err
}
return nil
}
func main() {
tunnelURI := os.Getenv("EC2SSH_TUNNEL_URI")
if len(os.Args) == 2 && os.Args[1] == "--wscat" && tunnelURI != "" {
/* Run in socat mode */
err := wscat.Run(tunnelURI)
if err != nil {
FatalError(err)
}
} else {
/* Run in normal mode otherwise */
if err := Run(os.Args[1:]); err != nil {
switch {
case errors.Is(err, ErrHelp):
Usage(nil)
case errors.Is(err, ErrArgParse):
Usage(err)
default:
FatalError(err)
}
}
}
}