mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-19 17:26:28 +00:00
Merge pull request #1323 from justincormack/gcp-metadata
Add a metadata handler for GCP which allows ssh login
This commit is contained in:
commit
a092d4352e
4
base/metadata-gcp/.gitignore
vendored
Normal file
4
base/metadata-gcp/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
dev
|
||||||
|
proc
|
||||||
|
sys
|
||||||
|
usr
|
3
base/metadata-gcp/Dockerfile
Normal file
3
base/metadata-gcp/Dockerfile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
FROM scratch
|
||||||
|
COPY . ./
|
||||||
|
CMD ["/usr/bin/metadata-gcp"]
|
44
base/metadata-gcp/Makefile
Normal file
44
base/metadata-gcp/Makefile
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
GO_COMPILE=mobylinux/go-compile:3afebc59c5cde31024493c3f91e6102d584a30b9@sha256:e0786141ea7df8ba5735b63f2a24b4ade9eae5a02b0e04c4fca33b425ec69b0a
|
||||||
|
|
||||||
|
SHA_IMAGE=alpine:3.5@sha256:dfbd4a3a8ebca874ebd2474f044a0b33600d4523d03b0df76e5c5986cb02d7e8
|
||||||
|
|
||||||
|
METADATA_BINARY=usr/bin/metadata-gcp
|
||||||
|
|
||||||
|
IMAGE=metadata-gcp
|
||||||
|
|
||||||
|
.PHONY: tag push clean container
|
||||||
|
default: push
|
||||||
|
|
||||||
|
$(METADATA_BINARY): gcp.go
|
||||||
|
mkdir -p $(dir $@)
|
||||||
|
tar cf - $^ | docker run --rm --net=none --log-driver=none -i $(GO_COMPILE) -o $@ | tar xf -
|
||||||
|
|
||||||
|
DIRS=dev proc sys
|
||||||
|
$(DIRS):
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
DEPS=$(DIRS) $(METADATA_BINARY)
|
||||||
|
|
||||||
|
container: Dockerfile $(DEPS)
|
||||||
|
tar cf - $^ | docker build --no-cache -t $(IMAGE):build -
|
||||||
|
|
||||||
|
hash: Dockerfile $(DEPS)
|
||||||
|
find $^ -type f | xargs cat | docker run --rm -i $(SHA_IMAGE) sha1sum - | sed 's/ .*//' > hash
|
||||||
|
|
||||||
|
push: hash container
|
||||||
|
docker pull mobylinux/$(IMAGE):$(shell cat hash) || \
|
||||||
|
(docker tag $(IMAGE):build mobylinux/$(IMAGE):$(shell cat hash) && \
|
||||||
|
docker push mobylinux/$(IMAGE):$(shell cat hash))
|
||||||
|
docker rmi $(IMAGE):build
|
||||||
|
rm -f hash
|
||||||
|
|
||||||
|
tag: hash container
|
||||||
|
docker pull mobylinux/$(IMAGE):$(shell cat hash) || \
|
||||||
|
docker tag $(IMAGE):build mobylinux/$(IMAGE):$(shell cat hash)
|
||||||
|
docker rmi $(IMAGE):build
|
||||||
|
rm -f hash
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf hash $(DIRS) usr
|
||||||
|
|
||||||
|
.DELETE_ON_ERROR:
|
75
base/metadata-gcp/gcp.go
Normal file
75
base/metadata-gcp/gcp.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
project = "http://metadata.google.internal/computeMetadata/v1/project/"
|
||||||
|
instance = "http://metadata.google.internal/computeMetadata/v1/instance/"
|
||||||
|
)
|
||||||
|
|
||||||
|
// If optional not set, will panic. Optional will allow 404
|
||||||
|
// We assume most failure cases are that this code is included in a non Google Cloud
|
||||||
|
// environment, which should generally be ok, so just fail fast.
|
||||||
|
func metadata(url string, optional bool) []byte {
|
||||||
|
var client = &http.Client{
|
||||||
|
Timeout: time.Second * 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("http NewRequest failed: %v", err)
|
||||||
|
}
|
||||||
|
req.Header.Set("Metadata-Flavor", "Google")
|
||||||
|
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
// Probably not running on Google Cloud but this package included
|
||||||
|
log.Fatalf("Could not contact Google Cloud Metadata service: %v", err)
|
||||||
|
}
|
||||||
|
if optional && resp.StatusCode == 404 {
|
||||||
|
return []byte{}
|
||||||
|
}
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
// Probably not running on Google Cloud but this package included
|
||||||
|
log.Fatalf("Google Cloud Metadata Server http error: %s", resp.Status)
|
||||||
|
}
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to read http response: %v", err)
|
||||||
|
}
|
||||||
|
return body
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
hostname := metadata(instance+"hostname", false)
|
||||||
|
err := syscall.Sethostname(hostname)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to set hostname: %v", err)
|
||||||
|
}
|
||||||
|
sshKeys := metadata(project+"attributes/sshKeys", true)
|
||||||
|
// TODO also retrieve the instance keys and respect block project keys see https://cloud.google.com/compute/docs/instances/ssh-keys
|
||||||
|
|
||||||
|
// the keys have usernames attached, but as a simplification we are going to add them all to one root file
|
||||||
|
// TODO split them into individual user files and make the ssh container construct those users
|
||||||
|
|
||||||
|
rootKeys := ""
|
||||||
|
for _, line := range strings.Split(string(sshKeys), "\n") {
|
||||||
|
parts := strings.SplitN(line, ":", 2)
|
||||||
|
// ignoring username for now
|
||||||
|
if len(parts) == 2 {
|
||||||
|
rootKeys = rootKeys + parts[1] + "\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ioutil.WriteFile("/etc/ssh/authorized_keys", []byte(rootKeys), 0600)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to write ssh keys: %v", err)
|
||||||
|
}
|
||||||
|
}
|
@ -46,10 +46,11 @@ type MobyImage struct {
|
|||||||
NetworkMode string `yaml:"network_mode"`
|
NetworkMode string `yaml:"network_mode"`
|
||||||
Pid string
|
Pid string
|
||||||
Ipc string
|
Ipc string
|
||||||
|
Uts string
|
||||||
ReadOnly bool `yaml:"read_only"`
|
ReadOnly bool `yaml:"read_only"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const riddler = "mobylinux/riddler:7d4545d8b8ac2700971a83f12a3446a76db28c14@sha256:11b7310df6482fc38aa52b419c2ef1065d7b9207c633d47554e13aa99f6c0b72"
|
const riddler = "mobylinux/riddler:8fe62ff02b9d28767554105b55d4613db3e77429@sha256:42b7f5c81fb85f8afb17548e00e5b81cfa4818c192e1199d61850491a178b0da"
|
||||||
|
|
||||||
// NewConfig parses a config file
|
// NewConfig parses a config file
|
||||||
func NewConfig(config []byte) (*Moby, error) {
|
func NewConfig(config []byte) (*Moby, error) {
|
||||||
@ -91,6 +92,10 @@ func ConfigToRun(order int, path string, image *MobyImage) []string {
|
|||||||
// TODO only "host" supported
|
// TODO only "host" supported
|
||||||
args = append(args, "--ipc="+image.Ipc)
|
args = append(args, "--ipc="+image.Ipc)
|
||||||
}
|
}
|
||||||
|
if image.Uts != "" {
|
||||||
|
// TODO only "host" supported
|
||||||
|
args = append(args, "--uts="+image.Uts)
|
||||||
|
}
|
||||||
for _, bind := range image.Binds {
|
for _, bind := range image.Binds {
|
||||||
args = append(args, "-v", bind)
|
args = append(args, "-v", bind)
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,16 @@ system:
|
|||||||
- /proc/sys/fs/binfmt_misc:/binfmt_misc
|
- /proc/sys/fs/binfmt_misc:/binfmt_misc
|
||||||
read_only: true
|
read_only: true
|
||||||
command: [/usr/bin/binfmt, -dir, /etc/binfmt.d/, -mount, /binfmt_misc]
|
command: [/usr/bin/binfmt, -dir, /etc/binfmt.d/, -mount, /binfmt_misc]
|
||||||
|
- name: metadata-gcp
|
||||||
|
image: "mobylinux/metadata-gcp:7fc3dd5ef92e0408fb3f76048bbaae88bbb55ad9"
|
||||||
|
binds:
|
||||||
|
- /tmp:/etc/ssh
|
||||||
|
- /etc/resolv.conf:/etc/resolv.conf
|
||||||
|
read_only: true
|
||||||
|
network_mode: host
|
||||||
|
uts: host
|
||||||
|
capabilities:
|
||||||
|
- CAP_SYS_ADMIN
|
||||||
daemon:
|
daemon:
|
||||||
- name: rngd
|
- name: rngd
|
||||||
image: "mobylinux/rngd:3dad6dd43270fa632ac031e99d1947f20b22eec9@sha256:1c93c1db7196f6f71f8e300bc1d15f0376dd18e8891c8789d77c8ff19f3a9a92"
|
image: "mobylinux/rngd:3dad6dd43270fa632ac031e99d1947f20b22eec9@sha256:1c93c1db7196f6f71f8e300bc1d15f0376dd18e8891c8789d77c8ff19f3a9a92"
|
||||||
@ -25,6 +35,21 @@ daemon:
|
|||||||
oom_score_adj: -800
|
oom_score_adj: -800
|
||||||
read_only: true
|
read_only: true
|
||||||
command: [/bin/tini, /usr/sbin/rngd, -f]
|
command: [/bin/tini, /usr/sbin/rngd, -f]
|
||||||
|
- name: sshd
|
||||||
|
image: "mobylinux/sshd:3940f3fa07da1b6adab975112894b103b3c491f1"
|
||||||
|
capabilities:
|
||||||
|
- CAP_NET_BIND_SERVICE
|
||||||
|
- CAP_CHOWN
|
||||||
|
- CAP_SETUID
|
||||||
|
- CAP_SETGID
|
||||||
|
- CAP_DAC_OVERRIDE
|
||||||
|
- CAP_SYS_CHROOT
|
||||||
|
- CAP_KILL
|
||||||
|
network_mode: host
|
||||||
|
binds:
|
||||||
|
- /tmp/authorized_keys:/root/.ssh/authorized_keys
|
||||||
|
- /etc/resolv.conf:/etc/resolv.conf
|
||||||
|
pid: host
|
||||||
- name: nginx
|
- name: nginx
|
||||||
image: "nginx:alpine"
|
image: "nginx:alpine"
|
||||||
capabilities:
|
capabilities:
|
||||||
|
@ -31,6 +31,7 @@ daemon:
|
|||||||
- CAP_SETGID
|
- CAP_SETGID
|
||||||
- CAP_DAC_OVERRIDE
|
- CAP_DAC_OVERRIDE
|
||||||
- CAP_SYS_CHROOT
|
- CAP_SYS_CHROOT
|
||||||
|
- CAP_KILL
|
||||||
network_mode: host
|
network_mode: host
|
||||||
binds:
|
binds:
|
||||||
- /root/.ssh:/root/.ssh
|
- /root/.ssh:/root/.ssh
|
||||||
|
@ -30,9 +30,17 @@ docker rm $CONTAINER > /dev/null
|
|||||||
# remove user namespaces
|
# remove user namespaces
|
||||||
# --read-only sets /dev ro
|
# --read-only sets /dev ro
|
||||||
# /sysfs ro unless privileged - cannot detect so will do if grant all caps
|
# /sysfs ro unless privileged - cannot detect so will do if grant all caps
|
||||||
#
|
# ipc, uts namespaces always isolated
|
||||||
|
|
||||||
|
UTS="."
|
||||||
|
IPC="."
|
||||||
|
echo $ARGS | grep -q uts=host && UTS=".linux.namespaces = (.linux.namespaces|map(select(.type!=\"uts\")))"
|
||||||
|
echo $ARGS | grep -q ipc=host && IPC=".linux.namespaces = (.linux.namespaces|map(select(.type!=\"ipc\")))"
|
||||||
|
|
||||||
mv config.json config.json.orig
|
mv config.json config.json.orig
|
||||||
cat config.json.orig | \
|
cat config.json.orig | \
|
||||||
|
jq "$UTS" | \
|
||||||
|
jq "$IPC" | \
|
||||||
jq 'del(.process.rlimits)' | \
|
jq 'del(.process.rlimits)' | \
|
||||||
jq 'del (.linux.resources.memory.swappiness)' | \
|
jq 'del (.linux.resources.memory.swappiness)' | \
|
||||||
jq 'del(.linux.uidMappings) | del(.linux.gidMappings) | .linux.namespaces = (.linux.namespaces|map(select(.type!="user")))' | \
|
jq 'del(.linux.uidMappings) | del(.linux.gidMappings) | .linux.namespaces = (.linux.namespaces|map(select(.type!="user")))' | \
|
||||||
|
Loading…
Reference in New Issue
Block a user