-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
INSECURE! The proxy intercepts GetObject and PutObject. A manual deployment guide is included. The decryption only relies on a hardcoded, static key. Do not use with sensitive data; testing only. * Ticket to track ranged GetObject: AB#3466.
- Loading branch information
Showing
13 changed files
with
1,233 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_cross_binary", "go_library") | ||
load("@rules_oci//oci:defs.bzl", "oci_image") | ||
load("@rules_pkg//:pkg.bzl", "pkg_tar") | ||
|
||
go_library( | ||
name = "cmd_lib", | ||
srcs = ["main.go"], | ||
importpath = "github.com/edgelesssys/constellation/v2/s3proxy/cmd", | ||
visibility = ["//visibility:private"], | ||
deps = [ | ||
"//internal/logger", | ||
"//s3proxy/internal/router", | ||
"@org_uber_go_zap//:zap", | ||
], | ||
) | ||
|
||
go_binary( | ||
name = "cmd", | ||
embed = [":cmd_lib"], | ||
visibility = ["//visibility:public"], | ||
) | ||
|
||
go_cross_binary( | ||
name = "s3proxy_linux_amd64", | ||
platform = "@io_bazel_rules_go//go/toolchain:linux_amd64", | ||
target = ":cmd", | ||
visibility = ["//visibility:public"], | ||
) | ||
|
||
pkg_tar( | ||
name = "layer", | ||
srcs = [ | ||
":s3proxy_linux_amd64", | ||
], | ||
mode = "0755", | ||
remap_paths = {"/s3proxy_linux_amd64": "/s3proxy"}, | ||
) | ||
|
||
oci_image( | ||
name = "s3proxy", | ||
base = "@distroless_static_linux_amd64", | ||
entrypoint = ["/s3proxy"], | ||
tars = [ | ||
":layer", | ||
], | ||
visibility = ["//visibility:public"], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
/* | ||
Copyright (c) Edgeless Systems GmbH | ||
SPDX-License-Identifier: AGPL-3.0-only | ||
*/ | ||
|
||
/* | ||
Package main parses command line flags and starts the s3proxy server. | ||
*/ | ||
package main | ||
|
||
import ( | ||
"crypto/tls" | ||
"flag" | ||
"fmt" | ||
"net" | ||
"net/http" | ||
|
||
"github.com/edgelesssys/constellation/v2/internal/logger" | ||
"github.com/edgelesssys/constellation/v2/s3proxy/internal/router" | ||
"go.uber.org/zap" | ||
) | ||
|
||
const ( | ||
// defaultPort is the default port to listen on. | ||
defaultPort = 4433 | ||
// defaultIP is the default IP to listen on. | ||
defaultIP = "0.0.0.0" | ||
// defaultRegion is the default AWS region to use. | ||
defaultRegion = "eu-west-1" | ||
// defaultCertLocation is the default location of the TLS certificate. | ||
defaultCertLocation = "/etc/s3proxy/certs" | ||
// defaultLogLevel is the default log level. | ||
defaultLogLevel = 0 | ||
) | ||
|
||
func main() { | ||
flags, err := parseFlags() | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
// logLevel can be made a public variable so logging level can be changed dynamically. | ||
// TODO (derpsteb): enable once we are on go 1.21. | ||
// logLevel := new(slog.LevelVar) | ||
// handler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: logLevel}) | ||
// logger := slog.New(handler) | ||
// logLevel.Set(flags.logLevel) | ||
|
||
logger := logger.New(logger.JSONLog, logger.VerbosityFromInt(flags.logLevel)) | ||
|
||
if err := runServer(flags, logger); err != nil { | ||
panic(err) | ||
} | ||
} | ||
|
||
func runServer(flags cmdFlags, log *logger.Logger) error { | ||
log.With(zap.String("ip", flags.ip), zap.Int("port", defaultPort), zap.String("region", flags.region)).Infof("listening") | ||
|
||
router := router.New(flags.region, log) | ||
|
||
server := http.Server{ | ||
Addr: fmt.Sprintf("%s:%d", flags.ip, defaultPort), | ||
Handler: http.HandlerFunc(router.Serve), | ||
// Disable HTTP/2. Serving HTTP/2 will cause some clients to use HTTP/2. | ||
// It seems like AWS S3 does not support HTTP/2. | ||
// Having HTTP/2 enabled will at least cause the aws-sdk-go V1 copy-object operation to fail. | ||
TLSNextProto: map[string]func(*http.Server, *tls.Conn, http.Handler){}, | ||
} | ||
|
||
// i.e. if TLS is enabled. | ||
if !flags.noTLS { | ||
cert, err := tls.LoadX509KeyPair(flags.certLocation+"/s3proxy.crt", flags.certLocation+"/s3proxy.key") | ||
if err != nil { | ||
return fmt.Errorf("loading TLS certificate: %w", err) | ||
} | ||
|
||
server.TLSConfig = &tls.Config{ | ||
Certificates: []tls.Certificate{cert}, | ||
} | ||
|
||
// TLSConfig is populated, so we can safely pass empty strings to ListenAndServeTLS. | ||
return server.ListenAndServeTLS("", "") | ||
} | ||
|
||
log.Warnf("TLS is disabled") | ||
return server.ListenAndServe() | ||
} | ||
|
||
func parseFlags() (cmdFlags, error) { | ||
noTLS := flag.Bool("no-tls", false, "disable TLS and listen on port 80, otherwise listen on 443") | ||
ip := flag.String("ip", defaultIP, "ip to listen on") | ||
region := flag.String("region", defaultRegion, "AWS region in which target bucket is located") | ||
certLocation := flag.String("cert", defaultCertLocation, "location of TLS certificate") | ||
level := flag.Int("level", defaultLogLevel, "log level") | ||
|
||
flag.Parse() | ||
|
||
netIP := net.ParseIP(*ip) | ||
if netIP == nil { | ||
return cmdFlags{}, fmt.Errorf("not a valid IPv4 address: %s", *ip) | ||
} | ||
|
||
// TODO(derpsteb): enable once we are on go 1.21. | ||
// logLevel := new(slog.Level) | ||
// if err := logLevel.UnmarshalText([]byte(*level)); err != nil { | ||
// return cmdFlags{}, fmt.Errorf("parsing log level: %w", err) | ||
// } | ||
|
||
return cmdFlags{noTLS: *noTLS, ip: netIP.String(), region: *region, certLocation: *certLocation, logLevel: *level}, nil | ||
} | ||
|
||
type cmdFlags struct { | ||
noTLS bool | ||
ip string | ||
region string | ||
certLocation string | ||
// TODO(derpsteb): enable once we are on go 1.21. | ||
// logLevel slog.Level | ||
logLevel int | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
# Deploying s3proxy | ||
|
||
Disclaimer: the following steps will be automated next. | ||
- Within `constellation/build`: `bazel run //:devbuild` | ||
- Copy the container name displayed for the s3proxy image. Look for the line starting with `[@//bazel/release:s3proxy_push]`. | ||
- Replace the image key in `deployment-s3proxy.yaml` with the image value you just copied. Use the sha256 hash instead of the tag to make sure you use the latest image. | ||
- Replace the `replaceme` values with valid AWS credentials. The s3proxy uses those credentials to access S3. | ||
- Run `kubectl apply -f deployment-s3proxy.yaml` | ||
|
||
# Deploying Filestash | ||
|
||
Filestash is a demo application that can be used to see s3proxy in action. | ||
To deploy Filestash, first deploy s3proxy as described above. | ||
Then run the below commands: | ||
|
||
```sh | ||
$ cat << EOF > "deployment-filestash.yaml" | ||
apiVersion: apps/v1 | ||
kind: Deployment | ||
metadata: | ||
name: filestash | ||
spec: | ||
replicas: 1 | ||
selector: | ||
matchLabels: | ||
app: filestash | ||
template: | ||
metadata: | ||
labels: | ||
app: filestash | ||
spec: | ||
imagePullSecrets: | ||
- name: regcred | ||
hostAliases: | ||
- ip: $(kubectl get svc s3proxy-service -o=jsonpath='{.spec.clusterIP}') | ||
hostnames: | ||
- "s3.eu-west-1.amazonaws.com" | ||
containers: | ||
- name: filestash | ||
image: machines/filestash:latest | ||
ports: | ||
- containerPort: 8334 | ||
volumeMounts: | ||
- name: ca-cert | ||
mountPath: /etc/ssl/certs/kube-ca.crt | ||
subPath: kube-ca.crt | ||
volumes: | ||
- name: ca-cert | ||
secret: | ||
secretName: s3proxy-tls | ||
items: | ||
- key: ca.crt | ||
path: kube-ca.crt | ||
EOF | ||
|
||
$ kubectl apply -f deployment-filestash.yaml | ||
``` | ||
|
||
Afterwards you can use a port forward to access the Filestash pod: | ||
- `kubectl port-forward pod/$(kubectl get pod --selector='app=filestash' -o=jsonpath='{.items[*].metadata.name}') 8443:8443` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
apiVersion: cert-manager.io/v1 | ||
kind: Issuer | ||
metadata: | ||
name: selfsigned-issuer | ||
labels: | ||
app: s3proxy | ||
spec: | ||
selfSigned: {} | ||
--- | ||
apiVersion: cert-manager.io/v1 | ||
kind: Certificate | ||
metadata: | ||
name: selfsigned-ca | ||
labels: | ||
app: s3proxy | ||
spec: | ||
isCA: true | ||
commonName: s3proxy-selfsigned-ca | ||
secretName: s3proxy-tls | ||
privateKey: | ||
algorithm: ECDSA | ||
size: 256 | ||
dnsNames: | ||
- "s3.eu-west-1.amazonaws.com" | ||
issuerRef: | ||
name: selfsigned-issuer | ||
kind: ClusterIssuer | ||
group: cert-manager.io | ||
--- | ||
apiVersion: apps/v1 | ||
kind: Deployment | ||
metadata: | ||
name: s3proxy | ||
labels: | ||
app: s3proxy | ||
spec: | ||
replicas: 1 | ||
selector: | ||
matchLabels: | ||
app: s3proxy | ||
template: | ||
metadata: | ||
labels: | ||
app: s3proxy | ||
spec: | ||
imagePullSecrets: | ||
- name: regcred | ||
containers: | ||
- name: s3proxy | ||
image: ghcr.io/edgelesssys/constellation/s3proxy@sha256:2394a804e8b5ff487a55199dd83138885322a4de8e71ac7ce67b79d4ffc842b2 | ||
args: | ||
- "--level=-1" | ||
ports: | ||
- containerPort: 4433 | ||
name: s3proxy-port | ||
volumeMounts: | ||
- name: tls-cert-data | ||
mountPath: /etc/s3proxy/certs/s3proxy.crt | ||
subPath: tls.crt | ||
- name: tls-cert-data | ||
mountPath: /etc/s3proxy/certs/s3proxy.key | ||
subPath: tls.key | ||
envFrom: | ||
- secretRef: | ||
name: s3-creds | ||
volumes: | ||
- name: tls-cert-data | ||
secret: | ||
secretName: s3proxy-tls | ||
- name: s3-creds | ||
secret: | ||
secretName: s3-creds | ||
--- | ||
apiVersion: v1 | ||
kind: Service | ||
metadata: | ||
name: s3proxy-service | ||
spec: | ||
selector: | ||
app: s3proxy | ||
ports: | ||
- name: https | ||
port: 443 | ||
targetPort: s3proxy-port | ||
type: ClusterIP | ||
--- | ||
apiVersion: v1 | ||
kind: Secret | ||
metadata: | ||
name: s3-creds | ||
type: Opaque | ||
stringData: | ||
AWS_ACCESS_KEY_ID: "replaceme" | ||
AWS_SECRET_ACCESS_KEY: "replaceme" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
load("@io_bazel_rules_go//go:def.bzl", "go_library") | ||
|
||
go_library( | ||
name = "crypto", | ||
srcs = ["crypto.go"], | ||
importpath = "github.com/edgelesssys/constellation/v2/s3proxy/internal/crypto", | ||
visibility = ["//s3proxy:__subpackages__"], | ||
) |
Oops, something went wrong.