Skip to content

Commit

Permalink
Use SQLite rather than mysql
Browse files Browse the repository at this point in the history
Resolves: #57

Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
  • Loading branch information
sarroutbi committed Aug 9, 2023
1 parent 277b684 commit 45de405
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 84 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
*~
http-server-x509-svid-parser
tang-iam-proxy
passphrase.txt
test_domain.key
*.pem
Expand Down
14 changes: 9 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM quay.io/sec-eng-special/mysql-server-deehms:latest
FROM fedora:latest

ENV SUMMARY="Tang IAM proxy" \
DESCRIPTION="Tang IAM proxy allows to redirect traffic to tang backend by SPIFFE ID" \
Expand All @@ -19,17 +19,21 @@ LABEL name="rhel9/tang-iam-proxy" \
io.openshift.tags="tang,tang-iam-proxy,container,NBDE,PBD,clevis,LUKS,McCallum-Relyea,Network Bound Disk Encryption"


RUN microdnf update -y && \
microdnf install -y \
RUN dnf update -y && \
dnf install -y \
iputils \
openssl \
procps-ng \
psmisc \
sqlite \
sqlite-libs \
vim && \
microdnf clean all && \
dnf clean all && \
rm -rf /var/cache/yum

COPY root /

VOLUME ["/var/db"]
VOLUME ["/var/lib/sqlite"]
EXPOSE ${PORT}

CMD ["/usr/bin/tang-iam-entrypoint.sh"]
20 changes: 14 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
BIN=tang-iam-proxy
ROOT_TARGET=root/usr/bin
RAW_ROOT_TARGET=root
ROOT_TARGET=$(RAW_ROOT_TARGET)/usr/bin
BIN_TARGET=$(ROOT_TARGET)/$(BIN)
VERSION?=0.0.1

.PHONY: all bin img clean test
.PHONY: all bin cert img clean test

all: bin img
all: bin cert img
echo "Building all ..."

cert:
./generate-signed-certificate.sh
mkdir -p $(ROOT_TARGET)
cp server_bundle.pem server.key $(ROOT_TARGET)

bin:
mkdir -p $(ROOT_TARGET)
cp generate-signed-certificate.sh $(ROOT_TARGET)
echo "$(VERSION)" > $(RAW_ROOT_TARGET)/version.txt
cp tang-iam-entrypoint.sh $(ROOT_TARGET)
cp tang-iam-health-check.sh $(ROOT_TARGET)
cp tang_bindings.db $(ROOT_TARGET)
go build -o $(BIN_TARGET) tang_iam_proxy.go

img:
podman build -t=quay.io/sec-eng-special/tang-iam-proxy-deehms:v$(VERSION) .
podman build -t=quay.io/sec-eng-special/tang-iam-proxy-deehms-sqlite:v$(VERSION) .

clean:
rm -f $(BIN_TARGET)
rm -fr $(ROOT_TARGET)
rm -f $(RAW_ROOT_TARGET)/version.txt
1 change: 1 addition & 0 deletions generate-signed-certificate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ EOF
openssl genrsa -out "${certname}.key" 4096
openssl req -new -key "${certname}.key" -out "${certname}.csr" -subj "/C=ES/ST=Madrid/L=Madrid/O=Red Hat/OU=org/CN=www.redhat.com"
openssl x509 -req -in "${certname}.csr" -CA "ca_${certname}_cert.pem" -CAkey "ca_${certname}.key" -out "${certname}.crt" -CAcreateserial -days 365 -sha256 -extfile "${certname}_cert_ext.cnf"
chmod 664 "${certname}.key"
########################################################################################
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ module main/tang-iam-proxy
go 1.19

require github.com/go-sql-driver/mysql v1.7.1
require github.com/mattn/go-sqlite3 v1.14.16
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
25 changes: 7 additions & 18 deletions tang-iam-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,11 @@
# limitations under the License.
#

db_command() {
echo "$1" | mysql --user=root --password=redhat123
}

if [ -z "$(ls -A /var/lib/mysql)" ]; then
mysqld --initialize &
echo "DB Initialized"
else
mysqld &
echo "DB reused"
fi
# Only copy database skeleton in case no database exist (fresh deployment)
test -f /var/lib/sqlite/tang_bindings.db || cp -rfv /usr/bin/tang_bindings.db /var/lib/sqlite
pushd /tmp || exit 1
generate-signed-certificate.sh
echo "Initialized"
db_command "UPDATE mysql.user SET host='%' WHERE user='root';" 2>/dev/null 1>/dev/null
db_command "grant all on db.* to 'root'@'127.0.0.1';" 2>/dev/null 1>/dev/null
db_command "CREATE DATABASE tang_bindings;" 2>/dev/null 1>/dev/null
db_command "USE tang_bindings; create table bindings (spiffe_id VARCHAR(255) NOT NULL, tang_workspace VARCHAR(255) NOT NULL);" 2>/dev/null 1>/dev/null
/usr/bin/tang-iam-proxy -dbUser root -dbPass redhat123 -httpUser jdoe -httpPass jdoe12345 -port 8000 -serverCert server_bundle.pem --serverKey server.key -tangServer TANG_SERVER_HERE
cp -v /usr/bin/server_bundle.pem .
cp -v /usr/bin/server.key .
# Uncomment sleep to connect and check tang iam proxy
# sleep 3600
/usr/bin/tang-iam-proxy -httpUser jdoe -httpPass jdoe12345 -port 8000 -serverCert server_bundle.pem --serverKey server.key -tangServer tang-backend-tang -insecure
Binary file added tang_bindings.db
Binary file not shown.
138 changes: 84 additions & 54 deletions tang_iam_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package main

import (
_ "github.com/mattn/go-sqlite3"
"crypto/tls"
"database/sql"
"encoding/base64"
Expand All @@ -28,22 +29,20 @@ import (
"os"
"strings"
"time"

_ "github.com/go-sql-driver/mysql"
)

const USAGE = `
usage:
tang_iam_proxy -serverCert <serverCertificateFile> -serverKey <serverPrivateKeyFile> -tangServer <tangServer>
[-port <port>] [-dbUser <dbuser>] [-dbPass <dbpass>] [-httpUser <httpuser>] [-httpPass <httppass>] [-help] [-verbose]
[-port <port>] [-dbFile <dbfile>] [-httpUser <httpuser>] [-httpPass <httppass>] [-insecure] [-help] [-verbose]
Options:
-help Optional, prints help message
-dbUser Optional, defaults to root
-dbPass Optional, database user password, defaults to redhat123
-dbFile Optional, defaults to /var/lib/sqlite/tang_bindings.db
-httpUser Optional, http user, defaults to jdoe
-httpPass Optional, http password, defaults to jdoe123
-insecure Optional, insecure more
-port Optional, the HTTPS port for the server to listen on, defaults to 443
-serverCert Mandatory, server's certificate file
-serverKey Mandatory, server's private key certificate file
Expand All @@ -57,38 +56,49 @@ const HTTP_READ_TIMEOUT = 5 * time.Second
const HTTP_WRITE_TIMEOUT = 5 * time.Second

// EE well known URL
const EE_URL = "/api/dee-hms/"
const EE_URL = "/api/tang-iam-proxy/"

// Global DB variable
var db *sql.DB

// printConnState prints information of the state of the connection and peer certificates, if any
func printConnState(r *http.Request) {
state := r.TLS
log.Print("**************** Connection State *****************")
log.Printf("Version: %x", state.Version)
log.Printf("HandshakeComplete: %t", state.HandshakeComplete)
log.Printf("DidResume: %t", state.DidResume)
log.Printf("CipherSuite: %x", state.CipherSuite)
log.Printf("NegotiatedProtocol: %s", state.NegotiatedProtocol)
log.Print("Certificate chain:")
for i, cert := range state.PeerCertificates {
subject := cert.Subject
issuer := cert.Issuer
log.Printf(" %d s:/C=%v/ST=%v/L=%v/O=%v/OU=%v/CN=%s", i, subject.Country, subject.Province,
subject.Locality, subject.Organization, subject.OrganizationalUnit, subject.CommonName)
log.Printf(" i:/C=%v/ST=%v/L=%v/O=%v/OU=%v/CN=%s", issuer.Country, issuer.Province,
issuer.Locality, issuer.Organization, issuer.OrganizationalUnit, issuer.CommonName)
for _, uri := range cert.URIs {
log.Printf(" SAN URL:[%v]", uri)
if state != nil {
log.Print("**************** Connection State *****************")
log.Printf("Version: %x", state.Version)
log.Printf("HandshakeComplete: %t", state.HandshakeComplete)
log.Printf("DidResume: %t", state.DidResume)
log.Printf("CipherSuite: %x", state.CipherSuite)
log.Printf("NegotiatedProtocol: %s", state.NegotiatedProtocol)
log.Print("Certificate chain:")
for i, cert := range state.PeerCertificates {
subject := cert.Subject
issuer := cert.Issuer
log.Printf(" %d s:/C=%v/ST=%v/L=%v/O=%v/OU=%v/CN=%s", i, subject.Country, subject.Province,
subject.Locality, subject.Organization, subject.OrganizationalUnit, subject.CommonName)
log.Printf(" i:/C=%v/ST=%v/L=%v/O=%v/OU=%v/CN=%s", issuer.Country, issuer.Province,
issuer.Locality, issuer.Organization, issuer.OrganizationalUnit, issuer.CommonName)
for _, uri := range cert.URIs {
log.Printf(" SAN URL:[%v]", uri)
}
}
log.Print("**************** /Connection State ****************")
} else {
log.Printf("WARNING: No TLS Information received")
}
log.Print("**************** /Connection State ****************")
}

// getSpiffeId returns spiffe id parsed from Subject Alternate Names
func getSpiffeId(r *http.Request) (string, error) {
state := r.TLS

// QUIT: remove this hack
// return "test_spiffe", nil

if state == nil {
return "", fmt.Errorf("getSpiffeId: no TLS in request")
}
for _, cert := range state.PeerCertificates {
for _, uri := range cert.URIs {
if strings.HasPrefix(uri.String(), "spiffe://") {
Expand Down Expand Up @@ -148,6 +158,42 @@ func addUserPassword(req *http.Request, audata AppData) {
req.Header.Add("Authorization", "Basic " + basicAuth(audata.user, audata.password))
}

// addWorkspaceToRequest
func (s *SimpleProxy) addWorkspaceToRequest(r *http.Request, workspace string) {
// modify request by adding workspace
originalPath := r.URL.Path
addUserPassword(r, AppData{user: s.appData.user, password: s.appData.password})
noHttpsTargetHost := strings.ReplaceAll(s.targetHost, "https://", "")
r.Header.Add("Host", noHttpsTargetHost)
log.Printf("URL Path %s\n", r.URL.Path)
log.Printf("Original Path %s\n", originalPath)
r.URL.Scheme = "https"
r.URL.Host = noHttpsTargetHost
r.Host = noHttpsTargetHost
// if the original path contains the well known path (/api/tang-iam-proxy/)
// set workspace after it
if strings.Contains(originalPath, EE_URL) {
suffix := strings.ReplaceAll(originalPath, EE_URL, "")
if(len(workspace) > 0) {
r.URL.Path = fmt.Sprintf("%s%s/%s", EE_URL, workspace, suffix)
} else {
r.URL.Path = fmt.Sprintf("%sWORKSPACE_NOT_FOUND/%s", EE_URL, suffix)
}
} else {
r.URL.Path = fmt.Sprintf("/%s%s", workspace, originalPath)
}
r.URL.Path = strings.ReplaceAll(r.URL.Path, "tang-iam-proxy", "dee-hms")
for k, v := range r.Header {
log.Printf("Header[%s]:%s", k, v)
if k == "X-Forwarded-Host" {
r.URL.Host = string(v[0])
r.Host = string(v[0])
}
}
log.Printf("Forwarding Request URL:[%s]\n", r.URL)
log.Printf("Forwarding Request:[%s]\n", r)

Check failure on line 194 in tang_iam_proxy.go

View workflow job for this annotation

GitHub Actions / lint

printf: log.Printf format %s has arg r of wrong type *net/http.Request (govet)
}

// ServeHTTP is request processing function
func (s *SimpleProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
log.Printf("Received %s request for host %s from IP address %s",
Expand All @@ -156,36 +202,17 @@ func (s *SimpleProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
spiffeId, err := getSpiffeId(r)
if err != nil {
log.Print(err)
http.Error(w, "not authorized!!", http.StatusUnauthorized)
http.Error(w, "Unable to parse spiffeID, not authorized!!", http.StatusBadRequest)
return
}
workspace, err := getWorkspace(spiffeId)
if err != nil {
log.Print(err)
http.Error(w, "not authorized!!", http.StatusUnauthorized)
http.Error(w, "Unable to locate workspace for spiffeId, forbidden!!", http.StatusForbidden)
return
}
log.Printf("tangWorkspace: %s", workspace)

// modify request by adding workspace
originalPath := r.URL.Path
// if the original path contains the well known EE path (/api/dee-hms/)
// set workspace after it
if strings.Contains(originalPath, EE_URL) {
suffix := strings.ReplaceAll(originalPath, EE_URL, "")
r.URL.Path = fmt.Sprintf("%s%s/%s", EE_URL, workspace, suffix)
} else {
r.URL.Path = fmt.Sprintf("/%s%s", workspace, originalPath)
}
addUserPassword(r, AppData{user: s.appData.user, password: s.appData.password})
noHttpsTargetHost := strings.ReplaceAll(s.targetHost, "https://", "")
r.Header.Add("Host", noHttpsTargetHost)
log.Printf("URL Path %s\n", r.URL.Path)
log.Printf("Original Path %s\n", originalPath)
for k, v := range r.Header {
log.Printf("Header[%s]:%s", k, v)
}
r.URL.Scheme = "https"
r.URL.Host = noHttpsTargetHost
r.Host = noHttpsTargetHost
s.addWorkspaceToRequest(r, workspace)
if s.appData.verbose {
sr, e := httputil.DumpRequestOut(r, false /*no body to print*/)
if e == nil {
Expand All @@ -196,7 +223,6 @@ func (s *SimpleProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
log.Printf("Request:[%s]", string(sr))
}
}

s.Proxy.ServeHTTP(w, r)
}

Expand All @@ -205,10 +231,10 @@ func main() {
var err error
help := flag.Bool("help", false, "Optional, prints help information")
port := flag.String("port", "443", "HTTPS port, defaults to 443")
dbUser := flag.String("dbUser", "root", "DB user, defaults to root")
dbPass := flag.String("dbPass", "", "DB Password, defaults to none")
dbFile := flag.String("dbFile", "/var/lib/sqlite/tang_bindings.db", "SQLite tang_bindings database file")
httpUser := flag.String("httpUser", "jdoe", "HTTP Authentication User, defaults to jdoe")
httpPass := flag.String("httpPass", "jdoe1123", "HTTP Authentication Password, defaults to jdoe123")
insecure := flag.Bool("insecure", false, "Optional, start in HTTP(no TLS) mode")
serverCert := flag.String("serverCert", "", "Mandatory, the name of the server's certificate file")
serverKey := flag.String("serverKey", "", "Mandatory, the file name of the server's private key file")
tangServer := flag.String("tangServer", "", "Mandatory, the server:port for the backend tang server")
Expand All @@ -227,8 +253,7 @@ func main() {
}

// Get a database handle.
dbConnectString := fmt.Sprintf("%s:%s@/tang_bindings", *dbUser, *dbPass)
db, err = sql.Open("mysql", dbConnectString)
db, err = sql.Open("sqlite3", *dbFile)
if err != nil {
log.Fatal(err)
}
Expand Down Expand Up @@ -257,6 +282,11 @@ func main() {

http.Handle("/", proxy)

log.Printf("Starting HTTPS server, port:[%v]", *port)
log.Fatal(server.ListenAndServeTLS(*serverCert, *serverKey))
if(*insecure) {
log.Printf("Starting HTTP server, port:[%v]", *port)
log.Fatal(server.ListenAndServe())
} else {
log.Printf("Starting HTTPS server, port:[%v]", *port)
log.Fatal(server.ListenAndServeTLS(*serverCert, *serverKey))
}
}

0 comments on commit 45de405

Please sign in to comment.