Waylon  Bruen

Waylon Bruen

1654668840

A Simple Implementation Of Some SSH Protocol Features in Go

easyssh-proxy    

easyssh-proxy provides a simple implementation of some SSH protocol features in Go.

Feature

This project is forked from easyssh but add some features as the following.

  •  Support plain text of user private key.
  •  Support key path of user private key.
  •  Support Timeout for the TCP connection to establish.
  •  Support SSH ProxyCommand.
     +--------+       +----------+      +-----------+
     | Laptop | <-->  | Jumphost | <--> | FooServer |
     +--------+       +----------+      +-----------+

                         OR

     +--------+       +----------+      +-----------+
     | Laptop | <-->  | Firewall | <--> | FooServer |
     +--------+       +----------+      +-----------+
     192.168.1.5       121.1.2.3         10.10.29.68

Usage

You can see ssh, scp, ProxyCommand on examples folder.

ssh

See example/ssh/ssh.go

package main

import (
    "fmt"
    "time"

    "github.com/appleboy/easyssh-proxy"
)

func main() {
    // Create MakeConfig instance with remote username, server address and path to private key.
    ssh := &easyssh.MakeConfig{
        User:   "appleboy",
        Server: "example.com",
        // Optional key or Password without either we try to contact your agent SOCKET
        // Password: "password",
        // Paste your source content of private key
        // Key: `-----BEGIN RSA PRIVATE KEY-----
        // MIIEpAIBAAKCAQEA4e2D/qPN08pzTac+a8ZmlP1ziJOXk45CynMPtva0rtK/RB26
        // 7XC9wlRna4b3Ln8ew3q1ZcBjXwD4ppbTlmwAfQIaZTGJUgQbdsO9YA==
        // -----END RSA PRIVATE KEY-----
        // `,
        KeyPath: "/Users/username/.ssh/id_rsa",
        Port:    "22",
        Timeout: 60 * time.Second,

        // Parse PrivateKey With Passphrase
        Passphrase: "1234",

        // Optional fingerprint SHA256 verification
        // Get Fingerprint: ssh.FingerprintSHA256(key)
        // Fingerprint: "SHA256:mVPwvezndPv/ARoIadVY98vAC0g+P/5633yTC4d/wXE"

        // Enable the use of insecure ciphers and key exchange methods.
        // This enables the use of the the following insecure ciphers and key exchange methods:
        // - aes128-cbc
        // - aes192-cbc
        // - aes256-cbc
        // - 3des-cbc
        // - diffie-hellman-group-exchange-sha256
        // - diffie-hellman-group-exchange-sha1
        // Those algorithms are insecure and may allow plaintext data to be recovered by an attacker.
        // UseInsecureCipher: true,
    }

    // Call Run method with command you want to run on remote server.
    stdout, stderr, done, err := ssh.Run("ls -al", 60*time.Second)
    // Handle errors
    if err != nil {
        panic("Can't run remote command: " + err.Error())
    } else {
        fmt.Println("don is :", done, "stdout is :", stdout, ";   stderr is :", stderr)
    }
}

scp

See example/scp/scp.go

package main

import (
    "fmt"

    "github.com/appleboy/easyssh-proxy"
)

func main() {
    // Create MakeConfig instance with remote username, server address and path to private key.
    ssh := &easyssh.MakeConfig{
        User:     "appleboy",
        Server:   "example.com",
        Password: "123qwe",
        Port:     "22",
    }

    // Call Scp method with file you want to upload to remote server.
    // Please make sure the `tmp` floder exists.
    err := ssh.Scp("/root/source.csv", "/tmp/target.csv")

    // Handle errors
    if err != nil {
        panic("Can't run remote command: " + err.Error())
    } else {
        fmt.Println("success")
    }
}

SSH ProxyCommand

See example/proxy/proxy.go

    ssh := &easyssh.MakeConfig{
        User:    "drone-scp",
        Server:  "localhost",
        Port:    "22",
        KeyPath: "./tests/.ssh/id_rsa",
        Proxy: easyssh.DefaultConfig{
            User:    "drone-scp",
            Server:  "localhost",
            Port:    "22",
            KeyPath: "./tests/.ssh/id_rsa",
        },
    }

SSH Stream Log

See example/stream/stream.go

func main() {
    // Create MakeConfig instance with remote username, server address and path to private key.
    ssh := &easyssh.MakeConfig{
        Server:  "localhost",
        User:    "drone-scp",
        KeyPath: "./tests/.ssh/id_rsa",
        Port:    "22",
        Timeout: 60 * time.Second,
    }

    // Call Run method with command you want to run on remote server.
    stdoutChan, stderrChan, doneChan, errChan, err := ssh.Stream("for i in {1..5}; do echo ${i}; sleep 1; done; exit 2;", 60*time.Second)
    // Handle errors
    if err != nil {
        panic("Can't run remote command: " + err.Error())
    } else {
        // read from the output channel until the done signal is passed
        isTimeout := true
    loop:
        for {
            select {
            case isTimeout = <-doneChan:
                break loop
            case outline := <-stdoutChan:
                fmt.Println("out:", outline)
            case errline := <-stderrChan:
                fmt.Println("err:", errline)
            case err = <-errChan:
            }
        }

        // get exit code or command error.
        if err != nil {
            fmt.Println("err: " + err.Error())
        }

        // command time out
        if !isTimeout {
            fmt.Println("Error: command timeout")
        }
    }
}

Author: Appleboy
Source Code: https://github.com/appleboy/easyssh-proxy 
License: MIT license

#go #golang #ssh #proxy 

What is GEEK

Buddha Community

A Simple Implementation Of Some SSH Protocol Features in Go
Fannie  Zemlak

Fannie Zemlak

1599854400

What's new in the go 1.15

Go announced Go 1.15 version on 11 Aug 2020. Highlighted updates and features include Substantial improvements to the Go linker, Improved allocation for small objects at high core counts, X.509 CommonName deprecation, GOPROXY supports skipping proxies that return errors, New embedded tzdata package, Several Core Library improvements and more.

As Go promise for maintaining backward compatibility. After upgrading to the latest Go 1.15 version, almost all existing Golang applications or programs continue to compile and run as older Golang version.

#go #golang #go 1.15 #go features #go improvement #go package #go new features

Waylon  Bruen

Waylon Bruen

1654668840

A Simple Implementation Of Some SSH Protocol Features in Go

easyssh-proxy    

easyssh-proxy provides a simple implementation of some SSH protocol features in Go.

Feature

This project is forked from easyssh but add some features as the following.

  •  Support plain text of user private key.
  •  Support key path of user private key.
  •  Support Timeout for the TCP connection to establish.
  •  Support SSH ProxyCommand.
     +--------+       +----------+      +-----------+
     | Laptop | <-->  | Jumphost | <--> | FooServer |
     +--------+       +----------+      +-----------+

                         OR

     +--------+       +----------+      +-----------+
     | Laptop | <-->  | Firewall | <--> | FooServer |
     +--------+       +----------+      +-----------+
     192.168.1.5       121.1.2.3         10.10.29.68

Usage

You can see ssh, scp, ProxyCommand on examples folder.

ssh

See example/ssh/ssh.go

package main

import (
    "fmt"
    "time"

    "github.com/appleboy/easyssh-proxy"
)

func main() {
    // Create MakeConfig instance with remote username, server address and path to private key.
    ssh := &easyssh.MakeConfig{
        User:   "appleboy",
        Server: "example.com",
        // Optional key or Password without either we try to contact your agent SOCKET
        // Password: "password",
        // Paste your source content of private key
        // Key: `-----BEGIN RSA PRIVATE KEY-----
        // MIIEpAIBAAKCAQEA4e2D/qPN08pzTac+a8ZmlP1ziJOXk45CynMPtva0rtK/RB26
        // 7XC9wlRna4b3Ln8ew3q1ZcBjXwD4ppbTlmwAfQIaZTGJUgQbdsO9YA==
        // -----END RSA PRIVATE KEY-----
        // `,
        KeyPath: "/Users/username/.ssh/id_rsa",
        Port:    "22",
        Timeout: 60 * time.Second,

        // Parse PrivateKey With Passphrase
        Passphrase: "1234",

        // Optional fingerprint SHA256 verification
        // Get Fingerprint: ssh.FingerprintSHA256(key)
        // Fingerprint: "SHA256:mVPwvezndPv/ARoIadVY98vAC0g+P/5633yTC4d/wXE"

        // Enable the use of insecure ciphers and key exchange methods.
        // This enables the use of the the following insecure ciphers and key exchange methods:
        // - aes128-cbc
        // - aes192-cbc
        // - aes256-cbc
        // - 3des-cbc
        // - diffie-hellman-group-exchange-sha256
        // - diffie-hellman-group-exchange-sha1
        // Those algorithms are insecure and may allow plaintext data to be recovered by an attacker.
        // UseInsecureCipher: true,
    }

    // Call Run method with command you want to run on remote server.
    stdout, stderr, done, err := ssh.Run("ls -al", 60*time.Second)
    // Handle errors
    if err != nil {
        panic("Can't run remote command: " + err.Error())
    } else {
        fmt.Println("don is :", done, "stdout is :", stdout, ";   stderr is :", stderr)
    }
}

scp

See example/scp/scp.go

package main

import (
    "fmt"

    "github.com/appleboy/easyssh-proxy"
)

func main() {
    // Create MakeConfig instance with remote username, server address and path to private key.
    ssh := &easyssh.MakeConfig{
        User:     "appleboy",
        Server:   "example.com",
        Password: "123qwe",
        Port:     "22",
    }

    // Call Scp method with file you want to upload to remote server.
    // Please make sure the `tmp` floder exists.
    err := ssh.Scp("/root/source.csv", "/tmp/target.csv")

    // Handle errors
    if err != nil {
        panic("Can't run remote command: " + err.Error())
    } else {
        fmt.Println("success")
    }
}

SSH ProxyCommand

See example/proxy/proxy.go

    ssh := &easyssh.MakeConfig{
        User:    "drone-scp",
        Server:  "localhost",
        Port:    "22",
        KeyPath: "./tests/.ssh/id_rsa",
        Proxy: easyssh.DefaultConfig{
            User:    "drone-scp",
            Server:  "localhost",
            Port:    "22",
            KeyPath: "./tests/.ssh/id_rsa",
        },
    }

SSH Stream Log

See example/stream/stream.go

func main() {
    // Create MakeConfig instance with remote username, server address and path to private key.
    ssh := &easyssh.MakeConfig{
        Server:  "localhost",
        User:    "drone-scp",
        KeyPath: "./tests/.ssh/id_rsa",
        Port:    "22",
        Timeout: 60 * time.Second,
    }

    // Call Run method with command you want to run on remote server.
    stdoutChan, stderrChan, doneChan, errChan, err := ssh.Stream("for i in {1..5}; do echo ${i}; sleep 1; done; exit 2;", 60*time.Second)
    // Handle errors
    if err != nil {
        panic("Can't run remote command: " + err.Error())
    } else {
        // read from the output channel until the done signal is passed
        isTimeout := true
    loop:
        for {
            select {
            case isTimeout = <-doneChan:
                break loop
            case outline := <-stdoutChan:
                fmt.Println("out:", outline)
            case errline := <-stderrChan:
                fmt.Println("err:", errline)
            case err = <-errChan:
            }
        }

        // get exit code or command error.
        if err != nil {
            fmt.Println("err: " + err.Error())
        }

        // command time out
        if !isTimeout {
            fmt.Println("Error: command timeout")
        }
    }
}

Author: Appleboy
Source Code: https://github.com/appleboy/easyssh-proxy 
License: MIT license

#go #golang #ssh #proxy 

Simple, Reliable, Persistent SSH Tunnels with Embedded SSH Server

Rospo 

Rospo is a tool meant to create secure and reliable SSH tunnels. A single binary includes both client and server. It's meant to make SSH tunnels fun and understendable again

Features

  • Easy to use (single binary client/server functionalities)
  • Encrypted connections through ssh ( crypto/ssh package )
  • Automatic connection monitoring to keep it always up
  • Embedded sshd server
  • Forward and reverse tunnels support
  • JumpHosts support
  • Command line options or human readable yaml config file
  • Run as a Windows Service support
  • Pty on Windows through conpty apis

How to Install

Rospo actually full supports *nix oses and Windows 10+

macOS

Homebrew

Install rospo using Homebrew

brew install rospo

GNU/Linux

Binary Download

PlatformArchitectureURL
GNU/Linuxamd64https://github.com/ferama/rospo/releases/latest/download/rospo-linux-amd64
 arm64https://github.com/ferama/rospo/releases/latest/download/rospo-linux-arm64
 armhttps://github.com/ferama/rospo/releases/latest/download/rospo-linux-arm

Microsoft Windows

Binary Download

PlatformArchitectureURL
Microsoft Windowsamd64https://github.com/ferama/rospo/releases/latest/download/rospo-windows-amd64.exe

Docker Container

You can use the docker ditribution where useful/needed. Look at an example on kubernetes here ./hack/k8s

docker pull ghcr.io/ferama/rospo
docker run ghcr.io/ferama/rospo rospo help

Quick command line usage

Rospo supports keys based auth and password auth. Keys based one is always the preferred, so it is better if identity, authorized_keys etc are always correctly setup.

Usage example:

Starts an embedded ssh server and reverse proxy the port (2222 by default) to remote_server

$ rospo revshell user@server:port

Forwards the local 5000 port to the remote 6000 on the remote_server

$ rospo tun forward -l :5000 -r :6000 user@server:port

Get more detailed help on each command runnig

$ rospo tun forward --help
$ rospo tun reverse --help
$ rospo sshd --help

For more complex use cases and more options, you can use a config file

$ rospo config.yaml

Look at the config_template.yaml for all the available options.

Rospo UI

Rospo supports a cool ui too. The ui will let you handle tunnels configuration at runtime through the web interface. You can start/stop new tunnels at runtime.

Tunnels that are configured through the rospo config file will not be administrable from the ui.

Image of Home

Image of tunnels

Scenarios

Example scenario: Windows reverse shell

Why use an embedded sshd server you might ask me. Suppose you have a Windows WSL instance that you want to access remotely without complicated setups on firewalls and other hassles and annoyances. With rospo you can do it in ONE simple step:

$ rospo revshell remote_ssh_server

This command will run an embedded sshd server on your wsl instance and reverse proxy its port to the remote_ssh_server

The only assumption here is that you have access to remote_ssh_server. The command will open a socket (on port 2222 by default) into remote_ssh_server that you can use to log back to WSL using a standard ssh client with a command like:

$ ssh -p 2222 localhost

Or even better (why not!) with rospo you can reverse proxy a powershell. Using rospo for windows:

rospo.exe revshell remote_ssh_server

Example scenario: Windows service

Rospo support execution as a service on windows. This means that you can create a persistent tunnel that can be installed as a service and started automatically with the machine.

Let's do this with the Windows Remote Desktop service.

Create a rospo conf file like this:

sshclient:
  server: your-rospo-or-sshd-server-uri:2222
  identity: "c:\\absolute_path_to_your\\id_rsa"
  known_hosts: "C:\\absolute_path_to_your\\known_hosts"

tunnel:
  - remote: :3389
    local: :3389  # the windows remote desktop port
    forward: false

Launch a terminal (powershell) with Administrative rights. You can then perform the following actions:

# create the rospo service
sc.exe create rospo start= auto DisplayName= Rospo binpath= "C:\rospo.exe C:\conf.yaml"

# start service
sc.exe start rospo

# query service status
sc.exe query rospo

# stop and delete the service
sc.exe stop rospo; sc.exe delete rospo

Example scenario: multiple complex tunnels

Rospo supports multiple tunnels on the same ssh connetion. To exploit the full power of rospo for more complex cases, you should/need to use a scenario config file. Let's define one. Create a file named config.yaml with the following contents

sshclient:
  server: myuser@remote_server_address
  identity: "~/.ssh/id_rsa"
  jump_hosts:
    - uri: anotheruser@jumphost_address
      identity: "~/.ssh/id_rsa"

tunnel:
  - remote: ":8000"
    local: ":8000"
    forward: yes
  - remote: ":9999"
    local: ":9999"
    forward: yes
  - remote: ":5000"
    local: ":5000"
    forward: no

Launch rospo using the config file instead of the cli parameters:

$ rospo config.yaml

What's happens here is that rospo will connect to remote_server_address through the jumphost_address server and will:

  1. open a socket on the local machine listening on port 8000 that forwards all the traffic to the service listening on port 8000 on the remote_server_address machine
  2. open a socket on the local machine listening on port 9999 that forwards all the traffic to the service listening on port 9999 on the remote_server_address machine
  3. open a socket on the remote machine listening on port 5000 that forwards all the traffic from remote machine to a local service (on the local machine) listening on port 5000

But these are just an examples. Rospo can do a lot more.

Tunnels are fully secured using standard ssh mechanisms. Rospo will generate server identity file on first run and uses standard authorized_keys and user known_hosts files.

Rospo tunnel are monitored and keeped up in the event of network issues.

Example scenario: kubernetes service exporter

Many times during development on k8s you need to port-forward some of the pods services for local development and/or tests. You need the port forward maybe because that services are not meant to be exposed through the internet or for whatever reason.

Rospo can come to the rescue here. You can create a rospo.conf like this:

sshclient:
  identity: "/etc/rospo/id_rsa"
  server: my-rospo-or-standard-sshd-server:2222
  known_hosts: "/etc/rospo/known_hosts"

tunnel:
  - remote: "0.0.0.0:9200"
    local: "elasticsearch-master.mynamespace:9200"
    forward: no
  - remote: "0.0.0.0:8080"
    local: "demo-app.mynamespace:8080"
    forward: no

You need to create the keys accordingly and put them correctly on the target server. After that you can run a kubernetes pod that keeps up the tunnels and let you securely access the services from a machine inside your local network. Please refer to the example in ./hack/k8s for more details.

In this scenario the k8s pods act as a bridge between kubernetes services and the reverse tunnels.

You are going to reverse forward the pod local reachable services ports to the desired host (my-rospo-or-standard-sshd-server:2222 in the example above)

Author: Ferama
Source Code: https://github.com/ferama/rospo 
License: MIT license

#go #golang #ssh #kubernetes 

Simplefeatures: Simple Features Is A Pure Go Implementation

Simple Features

Simple Features is a 2D geometry library that provides Go types that model geometries, as well as algorithms that operate on them.

It's a pure Go Implementation of the OpenGIS Consortium's Simple Feature Access Specification (which can be found here). This is the same specification that GEOS, JTS, and PostGIS implement, so the Simple Features API will be familiar to developers who have used those libraries before.

Table of Contents

Geometry Types

TypeExampleDescription
PointPoint is a single location in space.
MultiPointMultiPoint is collection of points in space.
LineStringLineString is curve defined by linear interpolation between a set of control points.
MultiLineStringMultiLineString is a collection of LineStrings.
PolygonPolygon is a planar surface geometry that bounds some area. It may have holes.
MultiPolygonPolygon is collection of Polygons (with some constraints on how the Polygons interact with each other).
GeometryCollectionGeometryCollection is an unconstrained collection of geometries.
GeometryGeometry holds any type of geometry (Point, MultiPoint, LineString, MultiLineString, Polygon, MultiPolygon, or GeometryCollection). It's the type that the Simple Features library uses when it needs to represent geometries in a generic way.
EnvelopeEnvelope is an axis aligned bounding box typically used to describe the spatial extent of other geometric entities.

Marshalling and Unmarshalling

Simple features supports the following external geometry representation formats:

FormatExampleDescription
WKTPOLYGON((0 0,0 1,1 1,1 0,0 0))Well Known Text is a human readable format for storing geometries. It's often the lowest common denominator geometry format, and is useful for integration with other GIS applications.
WKB<binary>Well Known Binary is a machine readable format that is efficient for computers to use (both from a processing and storage space perspective). WKB is a good choice for transferring geometries to and from PostGIS and other databases that support geometric types.
GeoJSON{"type":"Polygon","coordinates":[[[0,0],[0,1],[1,1],[1,0],[0,0]]]}GeoJSON represents geometries in a similar way to WKB, but is based on the JSON format. This makes it ideal to use with web APIs or other situations where JSON would normally be used.
TWKB<binary>Tiny Well Known Binary is a multi-purpose compressed binary format for serialising vector geometries into a stream of bytes. It emphasises minimising the size of the serialised representation. It's a good choice when space is at a premium (e.g. for storage within a web token).

Geometry Algorithms

The following algorithms are supported:

Miscellaneous AlgorithmsDescription
AreaFinds the area of the geometry (for Polygons and MultiPolygons).
CentroidFinds the centroid of the geometry.
ConvexHullFinds the convex hull of the geometry.
DistanceFinds the shortest distance between two geometries.
EnvelopeFinds the smallest axis-aligned bounding-box that surrounds the geometry.
ExactEqualsDetermines if two geometries are structurally equal.
LengthFinds the length of the geometry (for LineStrings and MultiLineStrings).
PointOnSurfaceFinds a point that lies inside the geometry.
RelateCalculates the DE-9IM intersection describing the relationship between two geometries.
SimplifySimplifies a geometry using the Ramer–Douglas–Peucker algorithm.
Set OperationsDescription
UnionJoins the parts from two geometries together.
IntersectionFinds the parts of two geometries that are in common.
DifferenceFinds the parts of a geometry that are not also part of another geometry.
SymmetricDifferenceFinds the parts of two geometries that are not in common.
Named Spatial PredicatesDescription
EqualsDetermines if two geometries are topologically equal.
IntersectsDetermines if two geometries intersect with each other.
DisjointDetermines if two geometries have no common points.
ContainsDetermines if one geometry contains another.
CoveredByDetermines if one geometry is covered by another.
CoversDetermines if one geometry covers another.
OverlapsDetermines if one geometry overlaps another.
TouchesDetermines if one geometry touches another.
WithinDetermines if one geometry is within another.
CrossesDetermines if one geometry crosses another.

GEOS Wrapper

A GEOS CGO wrapper is also provided, giving access to functionality not yet implemented natively in Go. The wrapper is implemented in a separate package, meaning that library users who don't need this additional functionality don't need to expose themselves to CGO.

Examples

The following examples show some common operations (errors are omitted for brevity).

WKT

Encoding and decoding WKT:

// Unmarshal from WKT
input := "POLYGON((0 0,0 1,1 1,1 0,0 0))"
g, _ := geom.UnmarshalWKT(input)

// Marshal to WKT
output := g.AsText()
fmt.Println(output) // Prints: POLYGON((0 0,0 1,1 1,1 0,0 0))

WKB

Encoding and decoding WKB directly:

// Marshal as WKB
coords := geom.Coordinates{XY: geom.XY{1.5, 2.5}}
pt := geom.NewPoint(coords)
wkb := pt.AsBinary()
fmt.Println(wkb) // Prints: [1 1 0 0 0 0 0 0 0 0 0 248 63 0 0 0 0 0 0 4 64]

// Unmarshal from WKB
fromWKB, _ := geom.UnmarshalWKB(wkb)
fmt.Println(fromWKB.AsText()) // POINT(1.5 2.5)

Encoding and decoding WKB for integration with PostGIS:

db, _ := sql.Open("postgres", "postgres://...")

db.Exec(`
    CREATE TABLE my_table (
        my_geom geometry(geometry, 4326),
        population double precision
    )`,
)

// Insert our geometry and population data into PostGIS via WKB.
coords := geom.Coordinates{XY: geom.XY{-74.0, 40.7}}
nyc := geom.NewPoint(coords)
db.Exec(`
    INSERT INTO my_table
    (my_geom, population)
    VALUES (ST_GeomFromWKB($1, 4326), $2)`,
    nyc, 8.4e6,
)

// Get the geometry and population data back out of PostGIS via WKB.
var location geom.Geometry
var population float64
db.QueryRow(`
    SELECT ST_AsBinary(my_geom), population
    FROM my_table LIMIT 1`,
).Scan(&location, &population)
fmt.Println(location.AsText(), population) // Prints: POINT(-74 40.7) 8.4e+06

GeoJSON

Encoding and decoding GeoJSON directly:

// Unmarshal geometry from GeoJSON.
raw := `{"type":"Point","coordinates":[-74.0,40.7]}`
var g geom.Geometry
json.NewDecoder(strings.NewReader(raw)).Decode(&g)
fmt.Println(g.AsText()) // Prints: POINT(-74 40.7)

// Marshal back to GeoJSON.
enc := json.NewEncoder(os.Stdout)
enc.Encode(g) // Prints: {"type":"Point","coordinates":[-74,40.7]}

Geometries can also be part of larger structs:

type CityPopulation struct {
    Location   geom.Geometry `json:"loc"`
    Population int           `json:"pop"`
}

// Unmarshal geometry from GeoJSON.
raw := `{"loc":{"type":"Point","coordinates":[-74.0,40.7]},"pop":8400000}`
var v CityPopulation
json.NewDecoder(strings.NewReader(raw)).Decode(&v)
fmt.Println(v.Location.AsText()) // Prints: POINT(-74 40.7)
fmt.Println(v.Population)        // Prints: 8400000

// Marshal back to GeoJSON.
enc := json.NewEncoder(os.Stdout)
enc.Encode(v) // Prints: {"loc":{"type":"Point","coordinates":[-74,40.7]},"pop":8400000}

Author: Peterstace
Source Code: https://github.com/peterstace/simplefeatures 
License: MIT License

#go #golang #library 

Nigel  Uys

Nigel Uys

1654831620

Skm: A Simple and Powerful SSH Keys Manager

SKM is a simple and powerful SSH Keys Manager. It helps you to manage your multiple SSH keys easily!

Features

  • Create, List, Delete your SSH key(s)
  • Manage all your SSH keys by alias names
  • Choose and set a default SSH key
  • Display public key via alias name
  • Copy default SSH key to a remote host
  • Rename SSH key alias name
  • Backup and restore all your SSH keys
  • Prompt UI for SSH key selection
  • Customized SSH key store path

Installation

Homebrew

brew tap timothyye/tap
brew install timothyye/tap/skm

Using Go

go get github.com/TimothyYe/skm/cmd/skm

Manual Installation

Download it from releases and extact it to /usr/bin or your PATH directory.

Usage

% skm

SKM V0.8.5
https://github.com/TimothyYe/skm

NAME:
   SKM - Manage your multiple SSH keys easily

USAGE:
   skm [global options] command [command options] [arguments...]

VERSION:
   0.8.5

COMMANDS:
     init, i      Initialize SSH keys store for the first time usage.
     create, c    Create a new SSH key.
     ls, l        List all the available SSH keys.
     use, u       Set specific SSH key as default by its alias name.
     delete, d    Delete specific SSH key by alias name.
     rename, rn   Rename SSH key alias name to a new one.
     copy, cp     Copy current SSH public key to a remote host.
     display, dp  Display the current SSH public key or specific SSH public key by alias name.
     backup, b    Backup all SSH keys to an archive file.
     restore, r   Restore SSH keys from an existing archive file.
     cache        Add your SSH to SSH agent cache via alias name.
     help, h      Shows a list of commands or help for one command.

GLOBAL OPTIONS:
   --store-path value   Path where SKM should store its profiles (default: "/Users/timothy/.skm")
   --ssh-path value     Path to a .ssh folder (default: "/Users/timothy/.ssh")
   --restic-path value  Path to the restic binary
   --help, -h           show help
   --version, -v        print the version

For the first time use

You should initialize the SSH key store for the first time use:

% skm init

✔ SSH key store initialized!

So, where are my SSH keys? SKM will create SSH key store at $HOME/.skm and put all the SSH keys in it.

NOTE: If you already have id_rsa & id_rsa.pub key pairs in $HOME/.ssh, SKM will move them to $HOME/.skm/default

Create a new SSH key

NOTE: Currently ONLY RSA and ED25519 keys are supported!

skm create prod -C "abc@abc.com"

Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/timothy/.skm/prod/id_rsa.
Your public key has been saved in /Users/timothy/.skm/prod/id_rsa.pub.
...
✔ SSH key [prod] created!

List SSH keys

% skm ls

✔ Found 3 SSH key(s)!

->      default
        dev
        prod

Set default SSH key

% skm use dev
Now using SSH key: dev

Prompt UI for key selection

You can just type skm use, then a prompt UI will help you to choose the right SSH key:

Display public key

% skm display

Or display specific SSH public key by alias name:

% skm display prod

Delete a SSH key

% skm delete prod

Please confirm to delete SSH key [prod] [y/n]: y
✔ SSH key [prod] deleted!

Copy SSH public key to a remote host

% skm cp timothy@example.com

/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/Users/timothy/.skm/default/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
timothy@example.com's password:

Number of key(s) added:        1

Now try logging into the machine, with:   "ssh 'timothy@example.com'"
and check to make sure that only the key(s) you wanted were added.

✔  Current SSH key already copied to remote host

Rename a SSH key with a new alias name

% skm rn test tmp
✔  SSH key [test] renamed to [tmp]

Backup SSH keys

Backup all your SSH keys to $HOME directory by default.

% skm backup

a .
a ./test
a ./default
a ./dev
a ./dev/id_rsa
a ./dev/id_rsa.pub
a ./default/id_rsa
a ./default/id_rsa.pub
a ./test/id_rsa
a ./test/id_rsa.pub

✔  All SSH keys backup to: /Users/timothy/skm-20171016170707.tar

If you have restic installed then you can also use that to create backups of your SKM store:

# First, you need a password for your repository
% if [[ ! -f ~/.skm-backups.passwd ]]; then
%     openssl rand -hex 64 > ~/.skm-backups.passwd
% fi

% skm backup --restic
repository ... opened successfully, password is correct

Files:           0 new,     1 changed,     4 unmodified
Dirs:            0 new,     0 changed,     0 unmodified
Added to the repo: 1.179 KiB

processed 5 files, 2.593 KiB in 0:00
snapshot $SNAPSHOT saved
✔  Backup to /Users/$USER/.skm-backups complete

Restore SSH keys

% skm restore ~/skm-20171016172828.tar.gz                                                                                           
x ./
x ./test/
x ./default/
x ./dev/
x ./dev/id_rsa
x ./dev/id_rsa.pub
x ./default/._id_rsa
x ./default/id_rsa
x ./default/._id_rsa.pub
x ./default/id_rsa.pub
x ./test/id_rsa
x ./test/id_rsa.pub

✔  All SSH keys restored to /Users/timothy/.skm

Again, SKM also supports restic to create and restore backups:

% skm restore --restic --restic-snapshot $SNAPSHOT
repository $REPO opened successfully, password is correct
restoring <Snapshot $SNAPSHOT of [/Users/$USER/.skm] at 2018-10-03 19:40:33.333130348 +0200 CEST by $USER@$HOST> to /Users/$USER/.skm
✔  Backup restored to /Users/$USER/.skm

Integrate with SSH agent

You can use cache command to cache your SSH key into SSH agent's cache via SSH alias name.

Cache your SSH key

λ tim [~/]
→ skm cache --add my                                                                                                                                                                                                                                                                     
Enter passphrase for /Users/timothy/.skm/my/id_rsa:
Identity added: /Users/timothy/.skm/my/id_rsa (/Users/timothy/.skm/my/id_rsa)
✔  SSH key [my] already added into cache

Remove your SSH key from cache

λ tim [~/]
→ ./skm cache --del my                                                                                                                                                                                                                                                                   
Identity removed: /Users/timothy/.skm/my/id_rsa (MyKEY)
✔  SSH key [my] removed from cache

List your cached SSH keys from SSH agent

λ tim [~/]
→ ./skm cache --list                                                                                                                                                                                                                                                                     
2048 SHA256:qAVcwc0tdUOCjH3sTskwxAmfMQiL2sKtfPBXFnUoZHQ /Users/timothy/.skm/my/id_rsa (RSA)

Customized SSH key store path

By default, SKM uses $HOME/.skm as the default path of SSH key store. You can define your customized key store path in your ~/.bashrc or ~/.zshrc by adding:

SKM_STORE_PATH=/usr/local/.skm

Hook mechanism

Edit and place a executable file named hook at the specified key directory, for example:

~/.skm/prod/hook

This hook file can be both an executable binary file or an executable script file.

SKM will call this hook file after switching default SSH key to it, you can do some stuff in this hook file.

For example, if you want to use different git username & email after you switch to use a different SSH key, you can create one hook file, and put shell commands in it:

#!/bin/bash
git config --global user.name "YourNewName"
git config --global user.email "YourNewEmail@example.com"

Then make this hook file executable:

chmod +x hook

SKM will call this hook file and change git global settings for you!

Author: TimothyYe
Source Code: https://github.com/TimothyYe/skm 
License: MIT license

#go #golang #ssh #key