diff --git a/backend/common/go.mod b/backend/common/go.mod index 8c16cf9e..c37f9322 100644 --- a/backend/common/go.mod +++ b/backend/common/go.mod @@ -27,7 +27,9 @@ require ( github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect go.opentelemetry.io/otel/trace v1.33.0 // indirect - golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect + golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e // indirect + golang.org/x/mod v0.22.0 // indirect + golang.org/x/sync v0.10.0 // indirect ) require ( @@ -58,7 +60,7 @@ require ( github.com/lestrrat-go/iter v1.0.2 // indirect github.com/lestrrat-go/option v1.0.1 // indirect github.com/magiconair/properties v1.8.9 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/mailru/easyjson v0.9.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -90,6 +92,7 @@ require ( require ( github.com/getsentry/sentry-go v0.30.0 github.com/go-playground/validator/v10 v10.23.0 + github.com/miekg/dns v1.1.62 github.com/valyala/bytebufferpool v1.0.0 // indirect go.opentelemetry.io/otel v1.33.0 // indirect go.uber.org/zap v1.27.0 diff --git a/backend/common/go.sum b/backend/common/go.sum index b27b3d61..042fd7cd 100644 --- a/backend/common/go.sum +++ b/backend/common/go.sum @@ -97,13 +97,15 @@ github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNB github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= +github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= @@ -185,8 +187,8 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU= -golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e h1:4qufH0hlUYs6AO6XmZC3GqfDPGSXHVXUFR6OND+iJX4= +golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= diff --git a/backend/common/helper/md5dns.go b/backend/common/helper/md5dns.go new file mode 100644 index 00000000..0576232e --- /dev/null +++ b/backend/common/helper/md5dns.go @@ -0,0 +1,48 @@ +package helper + +import ( + "crypto/hmac" + // Required due to the use in the MWN + "crypto/md5" //#nosec + "encoding/base64" + "encoding/hex" + + "github.com/miekg/dns" +) + +type Md5provider string + +func fromBase64(s []byte) (buf []byte, err error) { + buflen := base64.StdEncoding.DecodedLen(len(s)) + buf = make([]byte, buflen) + n, err := base64.StdEncoding.Decode(buf, s) + buf = buf[:n] + return +} + +func (key Md5provider) Generate(msg []byte, _ *dns.TSIG) ([]byte, error) { + // If we barf here, the caller is to blame + rawsecret, err := fromBase64([]byte(key)) + if err != nil { + return nil, err + } + h := hmac.New(md5.New, rawsecret) + + h.Write(msg) + return h.Sum(nil), nil +} + +func (key Md5provider) Verify(msg []byte, t *dns.TSIG) error { + b, err := key.Generate(msg, t) + if err != nil { + return err + } + mac, err := hex.DecodeString(t.MAC) + if err != nil { + return err + } + if !hmac.Equal(b, mac) { + return dns.ErrSig + } + return nil +} diff --git a/backend/dns-service/go.mod b/backend/dns-service/go.mod index df152f0a..8b3b47bb 100644 --- a/backend/dns-service/go.mod +++ b/backend/dns-service/go.mod @@ -24,7 +24,7 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/klauspost/compress v1.17.11 // indirect github.com/labstack/echo/v4 v4.13.2 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/mailru/easyjson v0.9.0 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect @@ -39,7 +39,7 @@ require ( github.com/swaggo/swag v1.16.4 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect golang.org/x/crypto v0.31.0 // indirect - golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect + golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e // indirect golang.org/x/sync v0.10.0 // indirect golang.org/x/time v0.8.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect @@ -76,7 +76,7 @@ require ( ) require ( - github.com/hm-edu/portal-common v0.0.0-20241210123407-8b7f3d70d1e8 + github.com/hm-edu/portal-common v0.0.0-20241213063548-4262a803d558 github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect ) diff --git a/backend/dns-service/go.sum b/backend/dns-service/go.sum index b4427e2f..8de9295b 100644 --- a/backend/dns-service/go.sum +++ b/backend/dns-service/go.sum @@ -97,8 +97,8 @@ github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0 github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -204,8 +204,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU= -golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e h1:4qufH0hlUYs6AO6XmZC3GqfDPGSXHVXUFR6OND+iJX4= +golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= diff --git a/backend/domain-rest-interface/go.mod b/backend/domain-rest-interface/go.mod index c3f4f719..dcf11b24 100644 --- a/backend/domain-rest-interface/go.mod +++ b/backend/domain-rest-interface/go.mod @@ -4,7 +4,7 @@ go 1.23.0 require ( github.com/getkin/kin-openapi v0.128.0 - github.com/hm-edu/portal-common v0.0.0-20241210123407-8b7f3d70d1e8 + github.com/hm-edu/portal-common v0.0.0-20241213063548-4262a803d558 go.opentelemetry.io/otel v1.33.0 // indirect go.uber.org/zap v1.27.0 google.golang.org/grpc v1.69.0 @@ -34,7 +34,7 @@ require ( github.com/go-openapi/swag v0.23.0 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/mailru/easyjson v0.9.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/swaggo/swag v1.16.4 go.opentelemetry.io/otel/trace v1.33.0 // indirect @@ -83,6 +83,7 @@ require ( github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgtype v1.14.4 // indirect github.com/klauspost/compress v1.17.11 // indirect + github.com/miekg/dns v1.1.62 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect @@ -98,7 +99,7 @@ require ( github.com/swaggo/files/v2 v2.0.1 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/otel/metric v1.33.0 // indirect - golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect + golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e // indirect golang.org/x/sync v0.10.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/backend/domain-rest-interface/go.sum b/backend/domain-rest-interface/go.sum index 409332fd..0c048a1e 100644 --- a/backend/domain-rest-interface/go.sum +++ b/backend/domain-rest-interface/go.sum @@ -216,8 +216,8 @@ github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -230,6 +230,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 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= +github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= +github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -377,8 +379,8 @@ golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZP golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU= -golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e h1:4qufH0hlUYs6AO6XmZC3GqfDPGSXHVXUFR6OND+iJX4= +golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= diff --git a/backend/eab-rest-interface/go.mod b/backend/eab-rest-interface/go.mod index aa1a5b3b..7c37ff6a 100644 --- a/backend/eab-rest-interface/go.mod +++ b/backend/eab-rest-interface/go.mod @@ -4,7 +4,7 @@ go 1.23.0 require ( github.com/getkin/kin-openapi v0.128.0 - github.com/hm-edu/portal-common v0.0.0-20241210123407-8b7f3d70d1e8 + github.com/hm-edu/portal-common v0.0.0-20241213063548-4262a803d558 github.com/smallstep/certificates v0.28.1 go.opentelemetry.io/otel v1.33.0 // indirect go.uber.org/zap v1.27.0 @@ -35,7 +35,7 @@ require ( github.com/go-openapi/swag v0.23.0 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/mailru/easyjson v0.9.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/swaggo/swag v1.16.4 go.opentelemetry.io/otel/trace v1.33.0 // indirect @@ -123,7 +123,7 @@ require ( github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.7 // indirect github.com/ghodss/yaml v1.0.0 // indirect - github.com/go-chi/chi/v5 v5.1.0 // indirect + github.com/go-chi/chi/v5 v5.2.0 // indirect github.com/go-jose/go-jose/v3 v3.0.3 // indirect github.com/go-jose/go-jose/v4 v4.0.4 // indirect github.com/go-openapi/inflect v0.21.0 // indirect @@ -172,7 +172,7 @@ require ( github.com/zclconf/go-cty v1.15.1 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect golang.org/x/crypto v0.31.0 // indirect - golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect + golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e // indirect golang.org/x/mod v0.22.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect golang.org/x/sync v0.10.0 // indirect diff --git a/backend/eab-rest-interface/go.sum b/backend/eab-rest-interface/go.sum index 83f802bd..7fd3e738 100644 --- a/backend/eab-rest-interface/go.sum +++ b/backend/eab-rest-interface/go.sum @@ -151,8 +151,8 @@ github.com/getsentry/sentry-go v0.30.0 h1:lWUwDnY7sKHaVIoZ9wYqRHJ5iEmoc0pqcRqFko github.com/getsentry/sentry-go v0.30.0/go.mod h1:WU9B9/1/sHDqeV8T+3VwwbjeR5MSXs/6aqG3mqZrezA= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= -github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0= +github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= @@ -358,8 +358,8 @@ github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= @@ -589,8 +589,8 @@ golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ss golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU= -golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e h1:4qufH0hlUYs6AO6XmZC3GqfDPGSXHVXUFR6OND+iJX4= +golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= diff --git a/backend/pki-rest-interface/go.mod b/backend/pki-rest-interface/go.mod index acaa1782..0e5085c5 100644 --- a/backend/pki-rest-interface/go.mod +++ b/backend/pki-rest-interface/go.mod @@ -5,7 +5,7 @@ go 1.23 require ( github.com/getkin/kin-openapi v0.128.0 github.com/hm-edu/portal-apis v0.0.0-20241128063248-b872e0b712f3 - github.com/hm-edu/portal-common v0.0.0-20241210123407-8b7f3d70d1e8 + github.com/hm-edu/portal-common v0.0.0-20241213063548-4262a803d558 github.com/johnbellone/grpc-middleware-sentry v0.4.0 github.com/labstack/echo/v4 v4.13.2 github.com/labstack/gommon v0.4.2 @@ -45,6 +45,7 @@ require ( github.com/magiconair/properties v1.8.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/miekg/dns v1.1.62 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect @@ -68,8 +69,11 @@ require ( go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/otel v1.33.0 // indirect go.opentelemetry.io/otel/metric v1.33.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.32.0 // indirect golang.org/x/crypto v0.31.0 // indirect - golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect + golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e // indirect + golang.org/x/mod v0.22.0 // indirect + golang.org/x/sync v0.10.0 // indirect golang.org/x/time v0.8.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect gopkg.in/ini.v1 v1.67.0 // indirect @@ -87,7 +91,7 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/mailru/easyjson v0.9.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/swaggo/swag v1.16.4 go.opentelemetry.io/otel/trace v1.33.0 // indirect diff --git a/backend/pki-rest-interface/go.sum b/backend/pki-rest-interface/go.sum index 9bcefc14..07d17908 100644 --- a/backend/pki-rest-interface/go.sum +++ b/backend/pki-rest-interface/go.sum @@ -132,13 +132,15 @@ github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNB github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= +github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= @@ -221,10 +223,10 @@ go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw= go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I= go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ= go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M= -go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= -go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= -go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc= -go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU= +go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -243,8 +245,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU= -golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e h1:4qufH0hlUYs6AO6XmZC3GqfDPGSXHVXUFR6OND+iJX4= +golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= diff --git a/backend/pki-rest-interface/pkg/api/docs/docs.go b/backend/pki-rest-interface/pkg/api/docs/docs.go index 889eb3bf..c896c1e9 100644 --- a/backend/pki-rest-interface/pkg/api/docs/docs.go +++ b/backend/pki-rest-interface/pkg/api/docs/docs.go @@ -39,6 +39,13 @@ const docTemplate = `{ "SMIME" ], "summary": "SMIME List Endpoint", + "parameters": [ + { + "type": "string", + "name": "email", + "in": "query" + } + ], "responses": { "200": { "description": "certificates", @@ -399,6 +406,9 @@ const docTemplate = `{ "portal_apis.SslCertificateDetails": { "type": "object", "properties": { + "ca": { + "type": "string" + }, "common_name": { "type": "string" }, diff --git a/backend/pki-service/cmd/run.go b/backend/pki-service/cmd/run.go index 8421f9fa..e909a7b1 100644 --- a/backend/pki-service/cmd/run.go +++ b/backend/pki-service/cmd/run.go @@ -31,8 +31,8 @@ var runCmd = &cobra.Command{ } // load Sectigo config - var sectigoCfg cfg.SectigoConfiguration - if err := viper.Unmarshal(§igoCfg); err != nil { + var pkiCfg cfg.PKIConfiguration + if err := viper.Unmarshal(&pkiCfg); err != nil { logger.Panic("config unmarshal failed", zap.Error(err)) } @@ -46,7 +46,7 @@ var runCmd = &cobra.Command{ stopCh := signals.SetupSignalHandler() - sectigoCfg.CheckSectigoConfiguration() + pkiCfg.CheckSectigoConfiguration() database.ConnectDb(logger, viper.GetString("db")) @@ -86,7 +86,7 @@ var runCmd = &cobra.Command{ s.StartAsync() // start gRPC server if grpcCfg.Port > 0 { - grpcSrv, _ := grpc.NewServer(&grpcCfg, logger, §igoCfg, database.DB.Db) + grpcSrv, _ := grpc.NewServer(&grpcCfg, logger, &pkiCfg, database.DB.Db) grpcSrv.ListenAndServe(stopCh) } }, @@ -119,4 +119,10 @@ func init() { runCmd.Flags().String("mail_to", "", "Optional param to send notifications to a specific mail address instead of the orignal issuer.") runCmd.Flags().String("mail_bcc", "", "Optional param to send notifications as blind copy to a specific mail address instead of the orignal issuer.") runCmd.Flags().String("mail_from", "", "The mail from") + runCmd.Flags().String("acme_storage", "", "Storage for the internal acme client") + runCmd.Flags().String("acme_email", "", "Email for the acme client") + runCmd.Flags().String("acme_hmac", "", "EAB HMAC for the acme client") + runCmd.Flags().String("acme_kid", "", "Key ID for the acme client") + runCmd.Flags().String("acme_server", "", "Server for the acme client") + runCmd.Flags().String("dns_configs", "", "Config file for the dns provider") } diff --git a/backend/pki-service/cmd/sync.go b/backend/pki-service/cmd/sync.go index 21c078cf..6fed0c80 100644 --- a/backend/pki-service/cmd/sync.go +++ b/backend/pki-service/cmd/sync.go @@ -25,7 +25,7 @@ var syncCmd = &cobra.Command{ defer deferFunc(logger) // load HTTP server config - var sectigoCfg cfg.SectigoConfiguration + var sectigoCfg cfg.PKIConfiguration if err := viper.Unmarshal(§igoCfg); err != nil { logger.Panic("config unmarshal failed", zap.Error(err)) } diff --git a/backend/pki-service/go.mod b/backend/pki-service/go.mod index edc8410d..34adb339 100644 --- a/backend/pki-service/go.mod +++ b/backend/pki-service/go.mod @@ -15,6 +15,12 @@ require ( require go.opentelemetry.io/auto/sdk v1.1.0 // indirect +require ( + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/magiconair/properties v1.8.9 // indirect + github.com/spf13/afero v1.11.0 // indirect +) + require ( ariga.io/atlas v0.29.0 // indirect github.com/KyleBanks/depth v1.2.1 // indirect @@ -25,6 +31,7 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/getkin/kin-openapi v0.128.0 // indirect + github.com/go-jose/go-jose/v4 v4.0.4 // indirect github.com/go-openapi/inflect v0.21.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect @@ -45,9 +52,10 @@ require ( github.com/klauspost/compress v1.17.11 // indirect github.com/labstack/echo/v4 v4.13.2 // indirect github.com/labstack/gommon v0.4.2 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/mailru/easyjson v0.9.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/miekg/dns v1.1.62 github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect @@ -69,13 +77,13 @@ require ( github.com/zclconf/go-cty v1.15.1 // indirect go.uber.org/atomic v1.11.0 // indirect golang.org/x/crypto v0.31.0 // indirect - golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect + golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e // indirect golang.org/x/mod v0.22.0 // indirect golang.org/x/sync v0.10.0 // indirect golang.org/x/time v0.8.0 // indirect golang.org/x/tools v0.28.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect + gopkg.in/yaml.v3 v3.0.1 ) require ( @@ -85,6 +93,7 @@ require ( github.com/hm-edu/portal-apis v0.0.0-20241128063248-b872e0b712f3 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 go.opentelemetry.io/otel v1.33.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect go.opentelemetry.io/otel/trace v1.33.0 // indirect go.uber.org/multierr v1.11.0 // indirect google.golang.org/protobuf v1.35.2 @@ -94,10 +103,8 @@ require ( github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/hm-edu/portal-common v0.0.0-20241210123407-8b7f3d70d1e8 - github.com/magiconair/properties v1.8.9 // indirect + github.com/hm-edu/portal-common v0.0.0-20241213063548-4262a803d558 github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.7.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect golang.org/x/net v0.32.0 // indirect @@ -109,6 +116,7 @@ require ( require ( entgo.io/ent v0.14.1 + github.com/go-acme/lego/v4 v4.20.4 github.com/go-co-op/gocron v1.37.0 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/inconshreveable/mousetrap v1.1.0 // indirect diff --git a/backend/pki-service/go.sum b/backend/pki-service/go.sum index fc2d1a6a..5aa7d2c4 100644 --- a/backend/pki-service/go.sum +++ b/backend/pki-service/go.sum @@ -21,6 +21,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0= github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -49,10 +51,14 @@ github.com/getkin/kin-openapi v0.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLb github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= github.com/getsentry/sentry-go v0.30.0 h1:lWUwDnY7sKHaVIoZ9wYqRHJ5iEmoc0pqcRqFkosKzBo= github.com/getsentry/sentry-go v0.30.0/go.mod h1:WU9B9/1/sHDqeV8T+3VwwbjeR5MSXs/6aqG3mqZrezA= +github.com/go-acme/lego/v4 v4.20.4 h1:yCQGBX9jOfMbriEQUocdYm7EBapdTp8nLXYG8k6SqSU= +github.com/go-acme/lego/v4 v4.20.4/go.mod h1:foauPlhnhoq8WUphaWx5U04uDc+JGhk4ZZtPz/Vqsjg= github.com/go-co-op/gocron v1.37.0 h1:ZYDJGtQ4OMhTLKOKMIch+/CY70Brbb1dGdooLEhh7b0= github.com/go-co-op/gocron v1.37.0/go.mod h1:3L/n6BkO7ABj+TrfSVXLRzsP26zmikL4ISkLQ0O8iNY= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= +github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -196,8 +202,8 @@ github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -210,6 +216,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 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= +github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= +github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -258,8 +266,9 @@ github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6g github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= +github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= @@ -316,8 +325,8 @@ go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw= go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I= go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ= go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M= -go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= -go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc= go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= @@ -361,8 +370,8 @@ golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZP golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU= -golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e h1:4qufH0hlUYs6AO6XmZC3GqfDPGSXHVXUFR6OND+iJX4= +golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= diff --git a/backend/pki-service/pkg/cfg/sectigo.go b/backend/pki-service/pkg/cfg/pki.go similarity index 78% rename from backend/pki-service/pkg/cfg/sectigo.go rename to backend/pki-service/pkg/cfg/pki.go index 6252e0d1..0dd660c6 100644 --- a/backend/pki-service/pkg/cfg/sectigo.go +++ b/backend/pki-service/pkg/cfg/pki.go @@ -9,8 +9,8 @@ import ( "go.uber.org/zap" ) -// SectigoConfiguration handles different configuration properties for the sectigo client -type SectigoConfiguration struct { +// PKIConfiguration handles different configuration properties for the sectigo client +type PKIConfiguration struct { User string `mapstructure:"sectigo_user"` Password string `mapstructure:"sectigo_password"` CustomerURI string `mapstructure:"sectigo_customeruri"` @@ -24,10 +24,16 @@ type SectigoConfiguration struct { SslTerm int `mapstructure:"ssl_term"` SmimeKeyLength string `mapstructure:"smime_key_length"` SmimeKeyType string `mapstructure:"smime_key_type"` + AcmeStorage string `mapstructure:"acme_storage"` + AcmeEmail string `mapstructure:"acme_email"` + AcmeKid string `mapstructure:"acme_kid"` + AcmeHmac string `mapstructure:"acme_hmac"` + AcmeServer string `mapstructure:"acme_server"` + DnsConfigs string `mapstructure:"dns_configs"` } // CheckSectigoConfiguration checks the sectigo configuration for the syntactical correctness. -func (cfg *SectigoConfiguration) CheckSectigoConfiguration() { +func (cfg *PKIConfiguration) CheckSectigoConfiguration() { logger := zap.L() diff --git a/backend/pki-service/pkg/grpc/server.go b/backend/pki-service/pkg/grpc/server.go index 594b81e2..7936686b 100644 --- a/backend/pki-service/pkg/grpc/server.go +++ b/backend/pki-service/pkg/grpc/server.go @@ -29,7 +29,7 @@ import ( type Server struct { logger *zap.Logger config *Config - sectigoCfg *cfg.SectigoConfiguration + sectigoCfg *cfg.PKIConfiguration db *ent.Client } @@ -41,7 +41,7 @@ type Config struct { } // NewServer creates a new GRPC server -func NewServer(config *Config, logger *zap.Logger, sectigoCfg *cfg.SectigoConfiguration, db *ent.Client) (*Server, error) { +func NewServer(config *Config, logger *zap.Logger, sectigoCfg *cfg.PKIConfiguration, db *ent.Client) (*Server, error) { srv := &Server{ logger: logger, sectigoCfg: sectigoCfg, diff --git a/backend/pki-service/pkg/grpc/smime.go b/backend/pki-service/pkg/grpc/smime.go index 8bac6953..10a258a3 100644 --- a/backend/pki-service/pkg/grpc/smime.go +++ b/backend/pki-service/pkg/grpc/smime.go @@ -27,11 +27,11 @@ import ( type smimeAPIServer struct { pb.UnimplementedSmimeServiceServer client *sectigo.Client - cfg *cfg.SectigoConfiguration + cfg *cfg.PKIConfiguration logger *zap.Logger } -func newSmimeAPIServer(client *sectigo.Client, cfg *cfg.SectigoConfiguration) *smimeAPIServer { +func newSmimeAPIServer(client *sectigo.Client, cfg *cfg.PKIConfiguration) *smimeAPIServer { return &smimeAPIServer{client: client, cfg: cfg, logger: zap.L()} } diff --git a/backend/pki-service/pkg/grpc/ssl.go b/backend/pki-service/pkg/grpc/ssl.go index 20cb669e..1c8ec2ec 100644 --- a/backend/pki-service/pkg/grpc/ssl.go +++ b/backend/pki-service/pkg/grpc/ssl.go @@ -2,24 +2,34 @@ package grpc import ( "context" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" "crypto/x509" + "encoding/json" "encoding/pem" "fmt" - "strings" + "os" + "path/filepath" "time" "github.com/TheZeroSlave/zapsentry" "github.com/getsentry/sentry-go" + legoCert "github.com/go-acme/lego/v4/certificate" + "github.com/go-acme/lego/v4/challenge/dns01" + "github.com/go-acme/lego/v4/lego" + legoLog "github.com/go-acme/lego/v4/log" + "github.com/hm-edu/pki-service/ent" "github.com/hm-edu/pki-service/ent/certificate" "github.com/hm-edu/pki-service/ent/domain" "github.com/hm-edu/pki-service/ent/predicate" "github.com/hm-edu/pki-service/pkg/cfg" pkiHelper "github.com/hm-edu/pki-service/pkg/helper" + "github.com/hm-edu/pki-service/pkg/helper/precheck" pb "github.com/hm-edu/portal-apis" "github.com/hm-edu/portal-common/helper" "github.com/hm-edu/sectigo-client/sectigo" - "github.com/hm-edu/sectigo-client/sectigo/ssl" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -50,6 +60,10 @@ func mapCertificate(x *ent.Certificate) *pb.SslCertificateDetails { if x.Source != nil { source = *x.Source } + ca := "" + if x.Ca != nil { + ca = *x.Ca + } return &pb.SslCertificateDetails{ Id: int32(x.SslId), DbId: int32(x.ID), @@ -62,6 +76,7 @@ func mapCertificate(x *ent.Certificate) *pb.SslCertificateDetails { Source: source, IssuedBy: issuedBy, Created: created, + Ca: ca, } } @@ -83,18 +98,20 @@ func (s *sslAPIServer) handleError(msg string, err error, logger *zap.Logger, hu type sslAPIServer struct { pb.UnimplementedSSLServiceServer - client *sectigo.Client - db *ent.Client - cfg *cfg.SectigoConfiguration - logger *zap.Logger + client *sectigo.Client + db *ent.Client + cfg *cfg.PKIConfiguration + logger *zap.Logger + legoClient *lego.Client last *time.Time duration *time.Duration } -func newSslAPIServer(client *sectigo.Client, cfg *cfg.SectigoConfiguration, db *ent.Client) *sslAPIServer { +func newSslAPIServer(client *sectigo.Client, cfg *cfg.PKIConfiguration, db *ent.Client) *sslAPIServer { - instance := &sslAPIServer{client: client, cfg: cfg, logger: zap.L(), db: db} + legoClient := registerAcme(cfg) + instance := &sslAPIServer{client: client, legoClient: legoClient, cfg: cfg, logger: zap.L(), db: db} _ = promauto.NewGaugeFunc(prometheus.GaugeOpts{ Name: "ssl_issue_last_duration", Help: "Required time for last SSL Certificates", @@ -118,6 +135,70 @@ func newSslAPIServer(client *sectigo.Client, cfg *cfg.SectigoConfiguration, db * return instance } +func registerAcme(cfg *cfg.PKIConfiguration) *lego.Client { + accountFile := filepath.Join(cfg.AcmeStorage, "reg.json") + keyFile := filepath.Join(cfg.AcmeStorage, "reg.key") + + var account pkiHelper.User + if ok, _ := pkiHelper.FileExists(accountFile); !ok { + // Actually we would not need a private key but the lego API requires one. + privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return nil + } + + account = pkiHelper.User{ + Key: privateKey, Email: cfg.AcmeEmail, + } + + } else { + data, err := os.ReadFile(accountFile) //#nosec + if err != nil { + return nil + } + err = json.Unmarshal(data, &account) + if err != nil { + return nil + } + account.Key, err = pkiHelper.LoadPrivateKey(keyFile) + if err != nil { + return nil + } + + } + legoCfg := lego.NewConfig(&account) + legoCfg.CADirURL = cfg.AcmeServer + legoLog.Logger = pkiHelper.NewZapLogger(zap.L()) + legoCfg.Certificate.Timeout = time.Duration(5) * time.Minute + if account.Registration == nil { + legoClient, err := lego.NewClient(legoCfg) + + if err != nil { + return nil + } + err = pkiHelper.RegisterAcme(legoClient, cfg, account, accountFile, keyFile) + if err != nil { + return nil + } + } + + legoClient, err := lego.NewClient(legoCfg) + if err != nil { + zap.L().Fatal("Failed to create lego client", zap.Error(err)) + } + dns, err := pkiHelper.NewDNSProvider(cfg.DnsConfigs) + if err != nil { + zap.L().Fatal("Failed to create DNS provider", zap.Error(err)) + } + + err = legoClient.Challenge.SetDNS01Provider(dns, dns01.WrapPreCheck(precheck.CheckDNS)) + if err != nil { + zap.L().Fatal("Failed to set DNS01 provider", zap.Error(err)) + } + + return legoClient +} + func (s *sslAPIServer) CertificateDetails(ctx context.Context, req *pb.CertificateDetailsRequest) (*pb.SslCertificateDetails, error) { x, err := s.db.Certificate.Query().WithDomains().Where(certificate.Serial(req.Serial)).First(ctx) if err != nil { @@ -218,6 +299,7 @@ func (s *sslAPIServer) IssueCertificate(ctx context.Context, req *pb.IssueSslReq SetCommonName(sans[0]). SetIssuedBy(req.Issuer). SetSource(req.Source). + SetCa("zerossl"). AddDomainIDs(ids...). Save(ctx) @@ -227,39 +309,15 @@ func (s *sslAPIServer) IssueCertificate(ctx context.Context, req *pb.IssueSslReq start := time.Now() hub.AddBreadcrumb(&sentry.Breadcrumb{Message: "Requesting certificate", Category: "info", Level: sentry.LevelInfo}, nil) - enrollment, err := s.client.SslService.Enroll(ssl.EnrollmentRequest{ - OrgID: s.cfg.SslOrgID, - Csr: req.Csr, - Term: s.cfg.SslTerm, - CertType: s.cfg.SslProfile, - SubjAltNames: strings.Join(req.SubjectAlternativeNames, ","), - }) - - if err != nil { - return s.handleError("Error while requesting certificate", err, logger, hub) - } - entry, err = s.db.Certificate.UpdateOneID(entry.ID).SetStatus(certificate.StatusRequested).SetSslId(enrollment.SslID).Save(ctx) + entry, err = s.db.Certificate.UpdateOneID(entry.ID).SetStatus(certificate.StatusRequested).Save(ctx) if err != nil { return s.handleError("Error while storing certificate", err, logger, hub) } - cert := "" - err = helper.WaitFor(5*time.Minute, 1*time.Second, func() (bool, error) { - c, err := s.client.SslService.Collect(enrollment.SslID, "x509R") - if err != nil { - if e, ok := err.(*sectigo.ErrorResponse); ok { - if e.Code == 0 && e.Description == "Being processed by Sectigo" { - s.logger.Debug("Certificate not ready", zap.Int("id", enrollment.SslID), zap.Strings("subject_alternative_names", req.SubjectAlternativeNames)) - return false, nil - } - } - return true, err - } - cert = *c - return true, nil - }) + + resp, err := s.legoClient.Certificate.ObtainForCSR(legoCert.ObtainForCSRRequest{CSR: csr, Bundle: true}) if err != nil { - return s.handleError("Error collecting certificate", err, logger, hub) + return s.handleError("Error while obtaining certificate", err, logger, hub) } hub.AddBreadcrumb(&sentry.Breadcrumb{Message: "Certificate collected", Category: "info", Level: sentry.LevelInfo}, nil) stop := time.Now() @@ -267,7 +325,7 @@ func (s *sslAPIServer) IssueCertificate(ctx context.Context, req *pb.IssueSslReq s.duration = &duration s.last = &stop - certs, err := pkiHelper.ParseCertificates([]byte(cert)) + certs, err := pkiHelper.ParseCertificates(resp.Certificate) if err != nil { return s.handleError("Error parsing certificate", err, logger, hub) } diff --git a/backend/pki-service/pkg/helper/acme.go b/backend/pki-service/pkg/helper/acme.go new file mode 100644 index 00000000..bd734629 --- /dev/null +++ b/backend/pki-service/pkg/helper/acme.go @@ -0,0 +1,106 @@ +package helper + +import ( + "crypto" + "crypto/x509" + "encoding/json" + "encoding/pem" + "errors" + "os" + + "github.com/go-acme/lego/v4/certcrypto" + "github.com/go-acme/lego/v4/lego" + "github.com/go-acme/lego/v4/registration" + "github.com/hm-edu/pki-service/pkg/cfg" +) + +// User represents an ACME user. +type User struct { + Email string + Registration *registration.Resource + Key crypto.PrivateKey +} + +// GetEmail returns the email of the user. +func (u *User) GetEmail() string { + return u.Email +} + +// GetRegistration returns the registration resource of the user. +func (u User) GetRegistration() *registration.Resource { + return u.Registration +} + +// GetPrivateKey returns the private key of the user. +func (u *User) GetPrivateKey() crypto.PrivateKey { + return u.Key +} + +// RegisterAcme performs a new registration and stores the registration in the given file. +func RegisterAcme(client *lego.Client, config *cfg.PKIConfiguration, account User, accountFile string, keyFile string) error { + reg, err := client.Registration.RegisterWithExternalAccountBinding( + registration.RegisterEABOptions{ + TermsOfServiceAgreed: true, + Kid: config.AcmeKid, + HmacEncoded: config.AcmeHmac, + }) + if err != nil { + return err + } + + account.Registration = reg + data, err := json.Marshal(account) + if err != nil { + return err + } + err = os.WriteFile(accountFile, data, 0600) + if err != nil { + return err + } + certOut, err := os.OpenFile(keyFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) //#nosec + if err != nil { + return err + } + + defer func(certOut *os.File) { + _ = certOut.Close() + }(certOut) + + pemKey := certcrypto.PEMBlock(account.Key) + err = pem.Encode(certOut, pemKey) + if err != nil { + return err + } + return nil +} + +// FileExists checks whether a file exists. +func FileExists(name string) (bool, error) { + _, err := os.Stat(name) + if err == nil { + return true, nil + } + if errors.Is(err, os.ErrNotExist) { + return false, nil + } + return false, err +} + +// LoadPrivateKey loads a private key from a file. +func LoadPrivateKey(file string) (crypto.PrivateKey, error) { + keyBytes, err := os.ReadFile(file) //#nosec + if err != nil { + return nil, err + } + + keyBlock, _ := pem.Decode(keyBytes) + + switch keyBlock.Type { + case "RSA PRIVATE KEY": + return x509.ParsePKCS1PrivateKey(keyBlock.Bytes) + case "EC PRIVATE KEY": + return x509.ParseECPrivateKey(keyBlock.Bytes) + } + + return nil, errors.New("unknown private key type") +} diff --git a/backend/pki-service/pkg/helper/dns.go b/backend/pki-service/pkg/helper/dns.go new file mode 100644 index 00000000..a7dd6be8 --- /dev/null +++ b/backend/pki-service/pkg/helper/dns.go @@ -0,0 +1,194 @@ +package helper + +import ( + "fmt" + "os" + "strings" + "time" + + "github.com/go-acme/lego/v4/challenge/dns01" + portalCommon "github.com/hm-edu/portal-common/helper" + "github.com/miekg/dns" + "go.uber.org/zap" + "gopkg.in/yaml.v3" +) + +const ( + // maximum time DNS client can be off from server for an update to succeed + clockSkew = 300 + + // maximum size of a UDP transport message in DNS protocol + udpMaxMsgSize = 512 +) + +type ProviderConfig struct { + BaseDomain string `yaml:"base_domain"` + ReadNameserver string `yaml:"read_nameserver"` + WriteNameserver string `yaml:"write_nameserver"` + TsigKeyName string `yaml:"tsig_key_name"` + TsigSecret string `yaml:"tsig_secret"` + TsigSecretAlg string `yaml:"tsig_secret_alg"` + Net string `yaml:"net"` +} + +type DNSProvider struct { + Configs []*ProviderConfig +} + +func NewDNSProvider(config string) (*DNSProvider, error) { + data, err := os.ReadFile(config) + if err != nil { + fmt.Println("Error reading config file: ", err) + return nil, err + } + + providerConfigs := make([]*ProviderConfig, 0) + err = yaml.Unmarshal(data, &providerConfigs) + + if err != nil { + fmt.Println("Error unmarshalling config file: ", err) + return nil, err + } + + return &DNSProvider{ + Configs: providerConfigs, + }, nil +} + +// List returns the current list of records. +func (r ProviderConfig) List() ([]dns.RR, error) { + m := new(dns.Msg) + m.SetAxfr(r.BaseDomain) + t := new(dns.Transfer) + t.TsigSecret = map[string]string{r.TsigKeyName: r.TsigSecret} + m.SetTsig(r.TsigKeyName, r.TsigSecretAlg, clockSkew, time.Now().Unix()) + if r.TsigSecretAlg == dns.HmacMD5 { + t.TsigProvider = portalCommon.Md5provider(r.TsigSecret) + } + env, err := t.In(m, r.ReadNameserver) + if err != nil { + return nil, fmt.Errorf("failed to fetch records: %v", err) + } + + records := make([]dns.RR, 0) + for e := range env { + if e.Error != nil { + continue + } + records = append(records, e.RR...) + } + + return records, nil +} + +// Add adds the given records to the zone. +func (r ProviderConfig) Add(entries []dns.RR) error { + m := new(dns.Msg) + m.SetUpdate(r.BaseDomain) + m.Insert(entries) + return r.sendMessage(m) + +} + +// Delete removes the given records from the zone. +func (r ProviderConfig) Delete(entries []dns.RR) error { + m := new(dns.Msg) + m.SetUpdate(r.BaseDomain) + m.Remove(entries) + return r.sendMessage(m) +} + +func (r ProviderConfig) sendMessage(msg *dns.Msg) error { + + c := new(dns.Client) + + c.TsigSecret = map[string]string{r.TsigKeyName: r.TsigSecret} + msg.SetTsig(r.TsigKeyName, r.TsigSecretAlg, clockSkew, time.Now().Unix()) + if r.TsigSecretAlg == dns.HmacMD5 { + c.TsigProvider = portalCommon.Md5provider(r.TsigSecret) + } + if msg.Len() > udpMaxMsgSize || r.Net == "tcp" { + c.Net = "tcp" + } + resp, _, err := c.Exchange(msg, r.WriteNameserver) + if resp == nil { + return fmt.Errorf("no response received") + } + if err != nil { + return err + } + if resp.Rcode != dns.RcodeSuccess { + return fmt.Errorf("bad return code: %s", dns.RcodeToString[resp.Rcode]) + } + return nil +} + +func (d *DNSProvider) Present(domain, token, keyAuth string) error { + info := dns01.GetChallengeInfo(domain, keyAuth) + // Get the DNS Provider with the best matching domain + // Check if the currently selected config is more specific than the previous one + matchingConfig, err := d.matchingProvider(info) + if err != nil { + return err + } + zap.L().Info("Using DNS provider for domain", zap.String("provider", matchingConfig.BaseDomain)) + + // Use the matching DNS provider to create the TXT record + rr := new(dns.TXT) + rr.Hdr = dns.RR_Header{Name: info.FQDN, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 60} + rr.Txt = []string{info.Value} + + err = matchingConfig.Add([]dns.RR{rr}) + if err != nil { + return fmt.Errorf("error adding TXT record: %v", err) + } + zap.L().Info("Successfully added TXT record", zap.String("fqdn", info.FQDN)) + return nil +} + +func (d *DNSProvider) matchingProvider(info dns01.ChallengeInfo) (*ProviderConfig, error) { + var matchingConfig *ProviderConfig + matchingConfig = nil + log := zap.L() + log.Info("Searching for DNS provider for domain", zap.String("fqdn", info.FQDN)) + for _, config := range d.Configs { + + if strings.HasSuffix(dns.Fqdn(info.FQDN), fmt.Sprintf(".%s", dns.Fqdn(config.BaseDomain))) { + if matchingConfig == nil { + matchingConfig = config + continue + } + + if len(strings.Split(config.BaseDomain, ".")) > len(strings.Split(matchingConfig.BaseDomain, ".")) { + matchingConfig = config + } + } else { + log.Info("Domain does not match", zap.String("fqdn", info.FQDN), zap.String("provider", config.BaseDomain)) + } + } + + if matchingConfig == nil { + return nil, fmt.Errorf("no matching DNS provider found for domain %s", info.FQDN) + } + return matchingConfig, nil +} + +func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error { + // clean up any state you created in Present, like removing the TXT record + info := dns01.GetChallengeInfo(domain, keyAuth) + // Get the DNS Provider with the best matching domain + provider, err := d.matchingProvider(info) + if err != nil { + return err + } + rr := new(dns.TXT) + rr.Hdr = dns.RR_Header{Name: info.FQDN, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 60} + rr.Txt = []string{info.Value} + + err = provider.Delete([]dns.RR{rr}) + if err != nil { + return fmt.Errorf("error deleting TXT record: %v", err) + } + + return nil +} diff --git a/backend/pki-service/pkg/helper/precheck/validation.go b/backend/pki-service/pkg/helper/precheck/validation.go new file mode 100644 index 00000000..5fa5ce54 --- /dev/null +++ b/backend/pki-service/pkg/helper/precheck/validation.go @@ -0,0 +1,91 @@ +package precheck + +import ( + "fmt" + "net" + "time" + + "github.com/go-acme/lego/v4/challenge/dns01" + "github.com/miekg/dns" + "go.uber.org/zap" +) + +func CheckDNS(domain, fqdn, value string, _ dns01.PreCheckFunc) (bool, error) { + for _, ns := range []string{"1.1.1.1", "8.8.8.8"} { + data, err := LookupTxt(fqdn, ns) + if err != nil { + return false, err + } + found := false + for _, txt := range data { + if txt == value { + found = true + continue + } + } + if !found { + return false, fmt.Errorf("TXT record not found") + } + } + zap.L().Sugar().Infof("TXT record found for %s", fqdn) + return true, nil +} + +var timeouts = []time.Duration{(time.Second * 1), (time.Second * 1), (time.Second * 2), (time.Second * 4), (time.Second * 2)} + +func ResolveWithTimeout(name, resolver string, qtype, qclass uint16) (*dns.Msg, error) { + client := new(dns.Client) + msg := &dns.Msg{ + MsgHdr: dns.MsgHdr{ + Id: dns.Id(), + RecursionDesired: true, + }, + Question: []dns.Question{{Name: dns.Fqdn(name), Qtype: qtype, Qclass: qclass}}, + } + msg.AuthenticatedData = true + msg.SetEdns0(4096, true) + + for i := 0; i < len(timeouts); i++ { + + client.Timeout = timeouts[i] + resp, _, err := client.Exchange(msg, fmt.Sprintf("%s:53", resolver)) + if err == nil && resp.Truncated { + tcpConn, _ := dns.Dial("tcp", fmt.Sprintf("%s:53", resolver)) + resp, _, err = client.ExchangeWithConn(msg, tcpConn) + } + if err != nil { + if err, ok := err.(net.Error); ok && err.Timeout() { + zap.L().Sugar().Warnf("Timeout querying %s records '%s' after %v", dns.TypeToString[qtype], name, timeouts[i]) + continue + } + return nil, err + } + + return resp, nil + + } + return nil, &net.DNSError{ + Name: name, + Err: "Final timeout.", + IsTimeout: true, + } +} + +func LookupTxt(name, resolver string) ([]string, error) { + zap.L().Sugar().Infof("Using custom resolver %s for lookup of %s", resolver, name) + resp, err := ResolveWithTimeout(name, resolver, dns.TypeTXT, dns.ClassINET) + if err != nil { + zap.L().Sugar().Warnf("Failed to lookup %s: %v", name, err) + return nil, err + } + data := []string{} + + // Check if TXT records are present + for _, answer := range resp.Answer { + if txt, ok := answer.(*dns.TXT); ok { + zap.L().Sugar().Infof("Resolved TXT records for %s: %s", name, txt.Txt) + data = append(data, txt.Txt...) + } + } + return data, nil +} diff --git a/backend/pki-service/pkg/helper/zap.go b/backend/pki-service/pkg/helper/zap.go new file mode 100644 index 00000000..0a678455 --- /dev/null +++ b/backend/pki-service/pkg/helper/zap.go @@ -0,0 +1,66 @@ +package helper + +import ( + "fmt" + "strings" + + "go.uber.org/zap" +) + +// ZapLogger wraps a zap.Logger for the lego client. +type ZapLogger struct { + logger *zap.Logger +} + +// NewZapLogger creates a new logger. +func NewZapLogger(logger *zap.Logger) *ZapLogger { + logger = logger.WithOptions(zap.AddCallerSkip(3)) + return &ZapLogger{ + logger: logger, + } +} + +// Fatal does logging in fatal level. +func (z *ZapLogger) Fatal(args ...interface{}) { + z.logger.Sugar().Fatal(args...) +} + +// Fatalln is in theory equivalent to Fatal, but followed by a line break. However, for ZAP both functions behave same +func (z *ZapLogger) Fatalln(args ...interface{}) { + z.Fatal(args...) +} + +// Fatalf is equivalent to Fatalln, but with formatting. +func (z *ZapLogger) Fatalf(format string, args ...interface{}) { + z.logger.Sugar().Fatalf(format, args...) +} + +// Print is equivalent to Println, but without the final line break. +func (z *ZapLogger) Print(args ...interface{}) { + msg := strings.TrimSpace(fmt.Sprint(args...)) + if strings.HasPrefix(msg, "[WARN]") { + z.logger.Sugar().Warn(strings.TrimSpace(strings.TrimPrefix(msg, "[WARN]"))) + } else if strings.HasPrefix(msg, "[INFO]") { + z.logger.Sugar().Info(strings.TrimSpace(strings.TrimPrefix(msg, "[INFO]"))) + } else { + z.logger.Sugar().Info(msg) + } +} + +// Println is in theory equivalent to Print, but followed by a line break. However, for ZAP both functions behave same +func (z *ZapLogger) Println(args ...interface{}) { + z.Print(args...) +} + +// Printf is equivalent to Print, but with formatting. +func (z *ZapLogger) Printf(format string, args ...interface{}) { + msg := strings.TrimSpace(fmt.Sprintf(format, args...)) + if strings.HasPrefix(msg, "[WARN]") { + z.logger.Sugar().Warn(strings.TrimSpace(strings.TrimPrefix(msg, "[WARN]"))) + } else if strings.HasPrefix(msg, "[INFO]") { + z.logger.Sugar().Info(strings.TrimSpace(strings.TrimPrefix(msg, "[INFO]"))) + } else { + z.logger.Sugar().Info(msg) + } + +} diff --git a/backend/validation-service/go.mod b/backend/validation-service/go.mod index dd30a53a..fd8dc698 100644 --- a/backend/validation-service/go.mod +++ b/backend/validation-service/go.mod @@ -25,7 +25,7 @@ require ( github.com/klauspost/compress v1.17.11 // indirect github.com/labstack/echo/v4 v4.13.2 // indirect github.com/labstack/gommon v0.4.2 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/mailru/easyjson v0.9.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect @@ -45,7 +45,7 @@ require ( github.com/valyala/fasttemplate v1.2.2 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect golang.org/x/crypto v0.31.0 // indirect - golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect + golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e // indirect golang.org/x/mod v0.22.0 // indirect golang.org/x/sync v0.10.0 // indirect golang.org/x/time v0.8.0 // indirect @@ -69,7 +69,7 @@ require ( require ( github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/hm-edu/portal-common v0.0.0-20241210123407-8b7f3d70d1e8 + github.com/hm-edu/portal-common v0.0.0-20241213063548-4262a803d558 github.com/magiconair/properties v1.8.9 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/spf13/afero v1.11.0 // indirect diff --git a/backend/validation-service/go.sum b/backend/validation-service/go.sum index d2333914..139af04b 100644 --- a/backend/validation-service/go.sum +++ b/backend/validation-service/go.sum @@ -74,8 +74,8 @@ github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0 github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -160,8 +160,8 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU= -golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e h1:4qufH0hlUYs6AO6XmZC3GqfDPGSXHVXUFR6OND+iJX4= +golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=