diff --git a/e2e/go.mod b/e2e/go.mod index c94ec87d..94948e4e 100644 --- a/e2e/go.mod +++ b/e2e/go.mod @@ -34,6 +34,7 @@ require ( dario.cat/mergo v1.0.2 // indirect filippo.io/edwards25519 v1.1.1 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect + github.com/Azure/go-ntlmssp v0.1.1 // indirect github.com/BobuSumisu/aho-corasick v1.0.3 // indirect github.com/DefangLabs/secret-detector v0.0.0-20250403165618-22662109213e // indirect github.com/Masterminds/goutils v1.1.1 // indirect @@ -148,6 +149,7 @@ require ( github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/hcl v1.0.0 // indirect @@ -159,6 +161,12 @@ require ( github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jcmturner/aescts/v2 v2.0.0 // indirect + github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect + github.com/jcmturner/gofork v1.7.6 // indirect + github.com/jcmturner/goidentity/v6 v6.0.1 // indirect + github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect + github.com/jcmturner/rpc/v2 v2.0.3 // indirect github.com/jedib0t/go-pretty v4.3.0+incompatible // indirect github.com/jonboulle/clockwork v0.5.0 // indirect github.com/josharian/intern v1.0.0 // indirect diff --git a/e2e/go.sum b/e2e/go.sum index 31e51aca..f12f8d6a 100644 --- a/e2e/go.sum +++ b/e2e/go.sum @@ -53,6 +53,8 @@ github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8af github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-ntlmssp v0.1.1 h1:l+FM/EEMb0U9QZE7mKNEDw5Mu3mFiaa2GKOoTSsNDPw= +github.com/Azure/go-ntlmssp v0.1.1/go.mod h1:NYqdhxd/8aAct/s4qSYZEerdPuH1liG2/X9DiVTbhpk= github.com/BobuSumisu/aho-corasick v1.0.3 h1:uuf+JHwU9CHP2Vx+wAy6jcksJThhJS9ehR8a+4nPE9g= github.com/BobuSumisu/aho-corasick v1.0.3/go.mod h1:hm4jLcvZKI2vRF2WDU1N4p/jpWtpOzp3nLmi9AzX/XE= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -490,6 +492,10 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORR github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gosimple/slug v1.15.0 h1:wRZHsRrRcs6b0XnxMUBM6WK1U1Vg5B0R7VkIf1Xzobo= @@ -521,6 +527,9 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= @@ -558,6 +567,18 @@ github.com/jackc/pgx/v5 v5.9.2 h1:3ZhOzMWnR4yJ+RW1XImIPsD1aNSz4T4fyP7zlQb56hw= github.com/jackc/pgx/v5 v5.9.2/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jedib0t/go-pretty v4.3.0+incompatible h1:CGs8AVhEKg/n9YbUenWmNStRW2PHJzaeDodcfvRAbIo= github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag= github.com/jinzhu/gorm v0.0.0-20170222002820-5409931a1bb8 h1:CZkYfurY6KGhVtlalI4QwQ6T0Cu6iuY3e0x5RLu96WE= @@ -1093,6 +1114,7 @@ golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= @@ -1184,6 +1206,7 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= diff --git a/go.mod b/go.mod index 9afaf520..30bbe4a3 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/Infisical/infisical-merge go 1.25.10 require ( + github.com/Azure/go-ntlmssp v0.1.1 github.com/BobuSumisu/aho-corasick v1.0.3 github.com/Masterminds/sprig/v3 v3.3.0 github.com/awnumar/memguard v0.23.0 @@ -21,6 +22,7 @@ require ( github.com/infisical/go-sdk v0.7.0 github.com/infisical/infisical-kmip v0.3.17 github.com/jackc/pgx/v5 v5.9.2 + github.com/jcmturner/gokrb5/v8 v8.4.4 github.com/mattn/go-isatty v0.0.20 github.com/muesli/ansi v0.0.0-20221106050444-61f0cd9a192a github.com/muesli/mango-cobra v1.2.0 @@ -115,10 +117,16 @@ require ( github.com/googleapis/gax-go/v2 v2.17.0 // indirect github.com/gosimple/slug v1.15.0 // indirect github.com/gosimple/unidecode v1.0.1 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/huandu/xstrings v1.5.0 // indirect github.com/imdario/mergo v0.3.6 // indirect + github.com/jcmturner/aescts/v2 v2.0.0 // indirect + github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect + github.com/jcmturner/gofork v1.7.6 // indirect + github.com/jcmturner/goidentity/v6 v6.0.1 // indirect + github.com/jcmturner/rpc/v2 v2.0.3 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.8 // indirect diff --git a/go.sum b/go.sum index ca309d55..e43fbce4 100644 --- a/go.sum +++ b/go.sum @@ -49,6 +49,8 @@ dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.1.1 h1:YpjwWWlNmGIDyXOn8zLzqiD+9TyIlPhGFG96P39uBpw= filippo.io/edwards25519 v1.1.1/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/Azure/go-ntlmssp v0.1.1 h1:l+FM/EEMb0U9QZE7mKNEDw5Mu3mFiaa2GKOoTSsNDPw= +github.com/Azure/go-ntlmssp v0.1.1/go.mod h1:NYqdhxd/8aAct/s4qSYZEerdPuH1liG2/X9DiVTbhpk= github.com/BobuSumisu/aho-corasick v1.0.3 h1:uuf+JHwU9CHP2Vx+wAy6jcksJThhJS9ehR8a+4nPE9g= github.com/BobuSumisu/aho-corasick v1.0.3/go.mod h1:hm4jLcvZKI2vRF2WDU1N4p/jpWtpOzp3nLmi9AzX/XE= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -328,6 +330,10 @@ github.com/googleapis/gax-go/v2 v2.17.0 h1:RksgfBpxqff0EZkDWYuz9q/uWsTVz+kf43LsZ github.com/googleapis/gax-go/v2 v2.17.0/go.mod h1:mzaqghpQp4JDh3HvADwrat+6M3MOIDp5YKHhb9PAgDY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gosimple/slug v1.15.0 h1:wRZHsRrRcs6b0XnxMUBM6WK1U1Vg5B0R7VkIf1Xzobo= github.com/gosimple/slug v1.15.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ= github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o= @@ -347,6 +353,9 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -377,6 +386,18 @@ github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7Ulw github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgx/v5 v5.9.2 h1:3ZhOzMWnR4yJ+RW1XImIPsD1aNSz4T4fyP7zlQb56hw= github.com/jackc/pgx/v5 v5.9.2/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jedib0t/go-pretty v4.3.0+incompatible h1:CGs8AVhEKg/n9YbUenWmNStRW2PHJzaeDodcfvRAbIo= github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -677,6 +698,7 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= @@ -760,6 +782,7 @@ golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= diff --git a/packages/api/model.go b/packages/api/model.go index cfebc509..75d9bcf0 100644 --- a/packages/api/model.go +++ b/packages/api/model.go @@ -955,6 +955,9 @@ type PAMSessionCredentials struct { ServiceAccountName string `json:"serviceAccountName,omitempty"` Namespace string `json:"namespace,omitempty"` Domain string `json:"domain,omitempty"` + Realm string `json:"realm,omitempty"` + KDCAddress string `json:"kdcAddress,omitempty"` + SPN string `json:"spn,omitempty"` } type MFASessionStatus string diff --git a/packages/pam/handlers/mssql/proxy.go b/packages/pam/handlers/mssql/proxy.go index 5073ba99..4d1c93d2 100644 --- a/packages/pam/handlers/mssql/proxy.go +++ b/packages/pam/handlers/mssql/proxy.go @@ -6,10 +6,15 @@ import ( "fmt" "io" "net" + "strings" "sync" "time" + "github.com/Azure/go-ntlmssp" "github.com/Infisical/infisical-merge/packages/pam/session" + "github.com/jcmturner/gokrb5/v8/client" + "github.com/jcmturner/gokrb5/v8/config" + "github.com/jcmturner/gokrb5/v8/spnego" "github.com/rs/zerolog/log" ) @@ -18,6 +23,11 @@ type MssqlProxyConfig struct { InjectUsername string InjectPassword string InjectDatabase string + InjectDomain string + InjectRealm string + InjectKDCAddr string + InjectSPN string + AuthMethod string // "sql-login", "ntlm", or "kerberos" EnableTLS bool TLSConfig *tls.Config SessionID string @@ -231,7 +241,22 @@ func (p *MssqlProxy) connectAndAuthenticateToServer() (net.Conn, []*TDSPacket, e log.Info().Str("sessionID", p.config.SessionID).Msg("TLS established with server") } - // 4. Send LOGIN7 with injected credentials + if p.config.AuthMethod == "ntlm" { + return p.authenticateNTLM(serverConn) + } + if p.config.AuthMethod == "kerberos" { + return p.authenticateKerberos(serverConn) + } + return p.authenticateSQL(serverConn) +} + +func (p *MssqlProxy) authenticateSQL(serverConn net.Conn) (_ net.Conn, _ []*TDSPacket, retErr error) { + defer func() { + if retErr != nil { + serverConn.Close() + } + }() + loginMsg := &Login7Message{ Username: p.config.InjectUsername, Password: p.config.InjectPassword, @@ -247,7 +272,6 @@ func (p *MssqlProxy) connectAndAuthenticateToServer() (net.Conn, []*TDSPacket, e Payload: loginMsg.Encode(), } if err := loginPkt.Write(serverConn); err != nil { - serverConn.Close() return nil, nil, fmt.Errorf("send login to server: %w", err) } @@ -257,11 +281,8 @@ func (p *MssqlProxy) connectAndAuthenticateToServer() (net.Conn, []*TDSPacket, e Int("loginPktLen", len(loginPkt.Payload)+TDSHeaderSize). Msg("Sent LOGIN7 to server") - // 5. Read login response - forward to client - log.Info().Str("sessionID", p.config.SessionID).Msg("Waiting for login response...") response, err := ReadAllPackets(serverConn) if err != nil { - serverConn.Close() return nil, nil, fmt.Errorf("read login response: %w", err) } log.Info(). @@ -271,11 +292,9 @@ func (p *MssqlProxy) connectAndAuthenticateToServer() (net.Conn, []*TDSPacket, e respPayload := CombinePayloads(response) if ContainsToken(respPayload, TokenError) { - serverConn.Close() return nil, nil, fmt.Errorf("server authentication failed") } if !ContainsToken(respPayload, TokenLoginAck) { - serverConn.Close() return nil, nil, fmt.Errorf("no login ack from server") } @@ -283,6 +302,220 @@ func (p *MssqlProxy) connectAndAuthenticateToServer() (net.Conn, []*TDSPacket, e return serverConn, response, nil } +func (p *MssqlProxy) authenticateNTLM(serverConn net.Conn) (_ net.Conn, _ []*TDSPacket, retErr error) { + defer func() { + if retErr != nil { + serverConn.Close() + } + }() + + negotiate, err := ntlmssp.NewNegotiateMessage(p.config.InjectDomain, "infisical-proxy") + if err != nil { + return nil, nil, fmt.Errorf("create NTLM negotiate message: %w", err) + } + + loginMsg := &Login7Message{ + Database: p.config.InjectDatabase, + AppName: "Infisical PAM Proxy", + Hostname: "infisical-proxy", + SSPIData: negotiate, + } + + loginPkt := &TDSPacket{ + Type: PacketTypeLogin7, + Status: StatusEOM, + PacketID: 1, + Payload: loginMsg.Encode(), + } + if err := loginPkt.Write(serverConn); err != nil { + return nil, nil, fmt.Errorf("send NTLM login to server: %w", err) + } + + log.Info(). + Str("sessionID", p.config.SessionID). + Str("domain", p.config.InjectDomain). + Str("user", p.config.InjectUsername). + Msg("Sent LOGIN7 with NTLM negotiate to server") + + challengeResponse, err := ReadAllPackets(serverConn) + if err != nil { + return nil, nil, fmt.Errorf("read NTLM challenge: %w", err) + } + + challengePayload := CombinePayloads(challengeResponse) + + challengeToken, err := ExtractSSPIToken(challengePayload) + if err != nil { + if ContainsToken(challengePayload, TokenError) { + return nil, nil, fmt.Errorf("server rejected NTLM negotiate") + } + return nil, nil, fmt.Errorf("extract NTLM challenge: %w", err) + } + + log.Info(). + Str("sessionID", p.config.SessionID). + Int("challengeLen", len(challengeToken)). + Msg("Received NTLM challenge from server") + + ntlmUsername := p.config.InjectDomain + "\\" + p.config.InjectUsername + authenticate, err := ntlmssp.ProcessChallenge(challengeToken, ntlmUsername, p.config.InjectPassword, true) + if err != nil { + return nil, nil, fmt.Errorf("process NTLM challenge: %w", err) + } + + sspiPkt := &TDSPacket{ + Type: PacketTypeSSPI, + Status: StatusEOM, + PacketID: 1, + Payload: authenticate, + } + if err := sspiPkt.Write(serverConn); err != nil { + return nil, nil, fmt.Errorf("send NTLM authenticate: %w", err) + } + + log.Info(). + Str("sessionID", p.config.SessionID). + Msg("Sent NTLM authenticate to server") + + response, err := ReadAllPackets(serverConn) + if err != nil { + return nil, nil, fmt.Errorf("read NTLM login response: %w", err) + } + + respPayload := CombinePayloads(response) + if ContainsToken(respPayload, TokenError) { + return nil, nil, fmt.Errorf("NTLM authentication failed") + } + if !ContainsToken(respPayload, TokenLoginAck) { + return nil, nil, fmt.Errorf("no login ack after NTLM authentication") + } + + log.Info().Str("sessionID", p.config.SessionID).Msg("MSSQL NTLM authentication successful") + return serverConn, response, nil +} + +func (p *MssqlProxy) authenticateKerberos(serverConn net.Conn) (_ net.Conn, _ []*TDSPacket, retErr error) { + defer func() { + if retErr != nil { + serverConn.Close() + } + }() + + cfg := buildKrb5Config(p.config.InjectRealm, p.config.InjectKDCAddr) + + krbClient := client.NewWithPassword( + p.config.InjectUsername, p.config.InjectRealm, p.config.InjectPassword, + cfg, client.DisablePAFXFAST(true), + ) + defer krbClient.Destroy() + + if err := krbClient.Login(); err != nil { + return nil, nil, wrapKerberosError(err, p.config.InjectKDCAddr) + } + + ticket, encryptionKey, err := krbClient.GetServiceTicket(p.config.InjectSPN) + if err != nil { + return nil, nil, wrapKerberosError(err, p.config.InjectKDCAddr) + } + + initToken, err := spnego.NewNegTokenInitKRB5(krbClient, ticket, encryptionKey) + if err != nil { + return nil, nil, fmt.Errorf("create SPNEGO token: %w", err) + } + + tokenBytes, err := initToken.Marshal() + if err != nil { + return nil, nil, fmt.Errorf("marshal SPNEGO token: %w", err) + } + + loginMsg := &Login7Message{ + Database: p.config.InjectDatabase, + AppName: "Infisical PAM Proxy", + Hostname: "infisical-proxy", + SSPIData: tokenBytes, + } + + loginPkt := &TDSPacket{ + Type: PacketTypeLogin7, + Status: StatusEOM, + PacketID: 1, + Payload: loginMsg.Encode(), + } + if err := loginPkt.Write(serverConn); err != nil { + return nil, nil, fmt.Errorf("send Kerberos login to server: %w", err) + } + + log.Info(). + Str("sessionID", p.config.SessionID). + Str("realm", p.config.InjectRealm). + Str("spn", p.config.InjectSPN). + Str("user", p.config.InjectUsername). + Msg("Sent LOGIN7 with Kerberos SPNEGO to server") + + response, err := ReadAllPackets(serverConn) + if err != nil { + return nil, nil, fmt.Errorf("read Kerberos login response: %w", err) + } + + respPayload := CombinePayloads(response) + + // Kerberos mutual auth: server may send SSPI accept before LoginAck. + // Read the next batch which should contain LoginAck. + if !ContainsToken(respPayload, TokenLoginAck) && !ContainsToken(respPayload, TokenError) { + response, err = ReadAllPackets(serverConn) + if err != nil { + return nil, nil, fmt.Errorf("read Kerberos final response: %w", err) + } + respPayload = CombinePayloads(response) + } + + if ContainsToken(respPayload, TokenError) { + return nil, nil, fmt.Errorf("Kerberos authentication failed") + } + if !ContainsToken(respPayload, TokenLoginAck) { + return nil, nil, fmt.Errorf("no login ack after Kerberos authentication") + } + + log.Info().Str("sessionID", p.config.SessionID).Msg("MSSQL Kerberos authentication successful") + return serverConn, response, nil +} + +func buildKrb5Config(realm, kdcAddress string) *config.Config { + cfg := config.New() + cfg.LibDefaults.DefaultRealm = realm + cfg.LibDefaults.DNSLookupKDC = kdcAddress == "" + cfg.LibDefaults.DNSLookupRealm = false + cfg.LibDefaults.UDPPreferenceLimit = 1 + + if kdcAddress != "" { + if !strings.Contains(kdcAddress, ":") { + kdcAddress = kdcAddress + ":88" + } + cfg.Realms = append(cfg.Realms, config.Realm{ + Realm: realm, + KDC: []string{kdcAddress}, + }) + } + + return cfg +} + +func wrapKerberosError(err error, kdcAddress string) error { + msg := err.Error() + switch { + case strings.Contains(msg, "sending to KDC") || strings.Contains(msg, "connection refused") || strings.Contains(msg, "dial timeout") || strings.Contains(msg, "i/o timeout"): + return fmt.Errorf("Kerberos: cannot reach KDC at %s (verify address and ensure port 88 is open): %w", kdcAddress, err) + case strings.Contains(msg, "Clock skew") || strings.Contains(msg, "KRB_AP_ERR_SKEW"): + return fmt.Errorf("Kerberos: clock skew too large (gateway and KDC must be within 5 minutes): %w", err) + case strings.Contains(msg, "Preauthentication") || strings.Contains(msg, "KDC_ERR_PREAUTH_FAILED"): + return fmt.Errorf("Kerberos: invalid credentials (check username, password, and realm): %w", err) + case strings.Contains(msg, "not found in Kerberos database") || strings.Contains(msg, "PRINCIPAL_UNKNOWN"): + return fmt.Errorf("Kerberos: principal not found (check realm and SPN): %w", err) + default: + return fmt.Errorf("Kerberos authentication failed: %w", err) + } +} + func (p *MssqlProxy) proxyToServer(client, server net.Conn, errCh chan error) { defer func() { if r := recover(); r != nil { diff --git a/packages/pam/handlers/mssql/tds.go b/packages/pam/handlers/mssql/tds.go index fe40845e..5e6b4dbe 100644 --- a/packages/pam/handlers/mssql/tds.go +++ b/packages/pam/handlers/mssql/tds.go @@ -53,6 +53,17 @@ const ( MaxPackets = 100 ) +var ntlmsspSignature = []byte("NTLMSSP\x00") + +// ExtractSSPIToken finds the NTLM token in a TDS server response by scanning for the NTLMSSP signature. +func ExtractSSPIToken(payload []byte) ([]byte, error) { + idx := bytes.Index(payload, ntlmsspSignature) + if idx < 0 { + return nil, fmt.Errorf("no NTLMSSP token found in server response") + } + return payload[idx:], nil +} + // TDSPacket represents a TDS packet type TDSPacket struct { Type uint8 @@ -294,6 +305,7 @@ type Login7Message struct { Password string AppName string Database string + SSPIData []byte } // ParseLogin7 parses a LOGIN7 message (extracts only what we need) @@ -324,7 +336,8 @@ const ( fSetLang = 0x80 // OptionFlags2 - fODBC = 0x02 + fODBC = 0x02 + fIntSecurity = 0x80 // Integrated Security (SSPI/NTLM) ) // Encode serializes the LOGIN7 message @@ -341,9 +354,19 @@ func (m *Login7Message) Encode() []byte { m.Header.OptionFlags1 = fUseDB | fSetLang m.Header.OptionFlags2 = fODBC + useSSPI := len(m.SSPIData) > 0 + hostname := encodeUTF16(m.Hostname) - username := encodeUTF16(m.Username) - password := manglePassword(m.Password) + var username, password []byte + if useSSPI { + // NTLM: username and password are empty in LOGIN7; auth is via SSPI blob + username = nil + password = nil + m.Header.OptionFlags2 |= fIntSecurity + } else { + username = encodeUTF16(m.Username) + password = manglePassword(m.Password) + } appname := encodeUTF16(m.AppName) database := encodeUTF16(m.Database) cltIntName := encodeUTF16("ODBC") // Client interface name @@ -385,12 +408,24 @@ func (m *Login7Message) Encode() []byte { offset += uint16(len(database)) m.Header.SSPIOffset = offset - m.Header.SSPILength = 0 + if useSSPI { + sspiLen := len(m.SSPIData) + if sspiLen < 65535 { + m.Header.SSPILength = uint16(sspiLen) + m.Header.SSPILongLength = 0 + } else { + m.Header.SSPILength = 0 + m.Header.SSPILongLength = uint32(sspiLen) + } + offset += uint16(sspiLen) + } else { + m.Header.SSPILength = 0 + m.Header.SSPILongLength = 0 + } m.Header.AtchDBFileOffset = offset m.Header.AtchDBFileLength = 0 m.Header.ChangePasswordOff = offset m.Header.ChangePasswordLen = 0 - m.Header.SSPILongLength = 0 m.Header.Length = uint32(offset) @@ -404,6 +439,9 @@ func (m *Login7Message) Encode() []byte { buf.Write(appname) buf.Write(cltIntName) buf.Write(database) + if useSSPI { + buf.Write(m.SSPIData) + } return buf.Bytes() } diff --git a/packages/pam/pam-proxy.go b/packages/pam/pam-proxy.go index 4ff5a37d..7e65e3e2 100644 --- a/packages/pam/pam-proxy.go +++ b/packages/pam/pam-proxy.go @@ -316,6 +316,11 @@ func HandlePAMProxy(ctx context.Context, conn *tls.Conn, pamConfig *GatewayPAMCo InjectUsername: credentials.Username, InjectPassword: credentials.Password, InjectDatabase: credentials.Database, + InjectDomain: credentials.Domain, + InjectRealm: credentials.Realm, + InjectKDCAddr: credentials.KDCAddress, + InjectSPN: credentials.SPN, + AuthMethod: credentials.AuthMethod, EnableTLS: credentials.SSLEnabled, TLSConfig: tlsConfig, SessionID: pamConfig.SessionId, diff --git a/packages/pam/session/credentials.go b/packages/pam/session/credentials.go index fcc9e3f1..d0e8e84d 100644 --- a/packages/pam/session/credentials.go +++ b/packages/pam/session/credentials.go @@ -35,6 +35,9 @@ type PAMCredentials struct { ServiceAccountName string Namespace string Domain string + Realm string + KDCAddress string + SPN string PolicyRules *api.PAMPolicyRules } @@ -188,6 +191,9 @@ func (cm *CredentialsManager) GetPAMSessionCredentials(sessionId string, expiryT ServiceAccountName: response.Credentials.ServiceAccountName, Namespace: response.Credentials.Namespace, Domain: response.Credentials.Domain, + Realm: response.Credentials.Realm, + KDCAddress: response.Credentials.KDCAddress, + SPN: response.Credentials.SPN, PolicyRules: response.PolicyRules, }