Merge pull request #1913 from openziti/release-next

Release 0.34.2
This commit is contained in:
Paul Lorenz
2024-04-08 12:42:08 -04:00
committed by GitHub
40 changed files with 1672 additions and 1058 deletions
+2 -1
View File
@@ -46,9 +46,10 @@ jobs:
uses: actions/checkout@v4
- name: Install Go
id: setup-go
uses: actions/setup-go@v5
with:
go-version: '1.22.x'
go-version-file: ./go.mod
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
+3 -2
View File
@@ -26,10 +26,11 @@ jobs:
with:
path: ziti
- name: Set up Go
- name: Install Go
id: setup-go
uses: actions/setup-go@v5
with:
go-version: '1.22.x'
go-version-file: ./go.mod
- name: Install Ziti CI
uses: openziti/ziti-ci@v1
+4 -3
View File
@@ -16,12 +16,13 @@ jobs:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Go
id: setup-go
uses: actions/setup-go@v5
with:
go-version: '1.22.x'
- uses: actions/checkout@v4
go-version-file: ./go.mod
- name: golangci-lint
uses: golangci/golangci-lint-action@v4
+7 -7
View File
@@ -46,7 +46,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.22.x'
go-version-file: ./go.mod
- name: Install Ziti CI
uses: openziti/ziti-ci@v1
@@ -80,7 +80,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.22.x'
go-version-file: ./go.mod
- name: Install Ziti CI
uses: openziti/ziti-ci@v1
@@ -111,7 +111,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.22.x'
go-version-file: ./go.mod
- name: Install Ziti CI
uses: openziti/ziti-ci@v1
@@ -147,7 +147,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.22.x'
go-version-file: ./go.mod
- name: Install Ziti CI
uses: openziti/ziti-ci@v1
@@ -178,7 +178,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.22.x'
go-version-file: ./go.mod
- name: Install Ziti CI
uses: openziti/ziti-ci@v1
@@ -301,7 +301,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.22.x'
go-version-file: ./go.mod
- name: Install Ziti CI
uses: openziti/ziti-ci@v1
@@ -416,7 +416,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.22.x'
go-version-file: ./go.mod
- name: Install Python
uses: actions/setup-python@v5
+6
View File
@@ -46,6 +46,12 @@ jobs:
- name: Checkout Workspace
uses: actions/checkout@v4
- name: Install Go
id: setup-go
uses: actions/setup-go@v5
with:
go-version-file: ./go.mod
- name: Install Ziti CI
uses: openziti/ziti-ci@v1
+1 -1
View File
@@ -33,7 +33,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.22.x'
go-version-file: ./go.mod
- name: Build and run a quickstart container image
shell: bash
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '1.22.x'
go-version-file: ./go.mod
- name: Install Ziti CI
uses: openziti/ziti-ci@v1
+19 -17
View File
@@ -29,20 +29,22 @@ open source that have embedded OpenZiti into the project, or use OpenZiti for se
Here's the list of projects which are proudly adopting and using OpenZiti
| Project Name | Project Link | Logo | How OpenZiti is used or why OpenZiti was chosen |
|----------------------------------|-----------------------------------------------|----------|-----------------|
| NetFoundry | https://nfconsole.io/signup | <img src="https://netfoundry.io/logos/Logo-Dark-Backgrounds.jpg" width="100px"> | NetFoundry SaaS provides management, orchestrations, support, and SLAs for OpenZiti networks. |
| HackBunker | https://www.hackbunker.com/ | <img src="https://irp.cdn-website.com/b429ad92/dms3rep/multi/hackbunker+logo+new.svg" width="100px"> | To open up a Zero Trust conversation in the C-Suite and Boardrooms of Blue-chip companies with a suite of products. |
| DeltaSecure GmbH | https://deltasecure.de/ | <img src="https://deltasecure.de/wp-content/uploads/2022/10/DeltaSecure-Logo-gross-hell.png.png" width="100px"> | To provide Managed Security Operations Center services for small and medium-sized enterprises. Ziti overlay forms the basis for secure data transmission of customer data and within the SOC infrastructure. |
| Resulticks | https://www.resulticks.com/ | <img src="https://www.resulticks.com/assets/platform/logos/resulticks-logo-blue.svg" width="100px"> | Resulticks Zero Trust API delivery network which forms the core of Resulticks' omnichannel marketing automation platform is built on OpenZiti to form a private dark mesh network. |
| KubeZT - Zero Trust Kubernetes | https://KubeZT.com/ | <img src="https://kubezt-public.s3-us-gov-east-1.amazonaws.com/github-org-logo.png" width="100px"> | KubeZT is an on-demand Kubernetes environment that enables developers to build and deploy highly secure applications for high-compliance organizations. |
| Analytics HQ | https://AnalyticsHQ.com/ | <img src="https://ahq-public.s3-us-gov-west-1.amazonaws.com/ahq-logo.png" width="100px"> | Analytics HQ is a next-generation unified platform built for modern data management and advanced analytics. |
| PITS Global Data Recovery Services | https://www.pitsdatarecovery.net/ | <img src="https://www.pitsdatarecovery.net/wp-content/uploads/2020/09/pits-logo.svg" width="100px"> | PITS Global Data Recovery Services is a data recovery company in the United States that offers services for recovering data from hard drives, SSDs, flash drives, RAID arrays and more. |
| KEOIC | http://www.keoic.com/ | <img src="https://static.wixstatic.com/media/300f00_ebca9ecefd8743eb82769e1d3079e55a~mv2.jpg" width="100px"> | KEO International Consultants is a multifaceted AEC firm with a presence across the Middle East and Europe. KEO uses the CloudZiti platform to facilitate zero-trust connections for users, devices, and applications throughout their worldwide network of branch offices and sites. |
| ChirpWireless | https://chirpwireless.io/ | <img src="https://docs.chirptoken.io/img/logo.svg" width="100px"> | Chirp is a project at the forefront of the DePIN (Decentralized physical infrastructure) movement, revolutionizing the world of wireless connectivity. It's a global telecommunications network that offers wireless internet and IoT connectivity for both residential and commercial use. OpenZiti overlay network is used for management of our LoRaWAN gateway miners ("Blackbirds") across multiple countries, allowing them to be dark. |
| GIGO Dev | https://gigo.dev/ | <img src="https://gigo.dev/logo192.png" width="100px"> | GIGO Dev is a learn-to-code platform that focuses on aligning learning with the real world of development. On GIGO you work in DevSpaces (Cloud Development Environments) capable of running nearly any system configuration needed for the challenge. We use OpenZiti to dynamically and securely expose network applications inside your DevSpace. Ziti provides the simplest, easiest, and most reliable system to securely route traffic into the local network of your DevSpace. |
| Underground Nexus | https://github.com/Underground-Ops/underground-nexus | <img src="https://raw.githubusercontent.com/Underground-Ops/underground-nexus/18d63a02aad41d8f540a044d5dd47f025d2b61a1/Graphics/SVG/cloud-underground-logo.svg" width="100px"> | Cloud Underground has chosen OpenZiti to integrate with our project called the Underground Nexus. OpenZiti provides our project with a unique way to maintain Zero Trust networking using it's overlay system to produce networks that don't require applications to be exposed to the public web - without the use of a VPN. |
| Ubitech | https://ubitech.eu/ | <img src="https://ubitech.eu/wp-content/uploads/logo.png" width="100px"> | UBITECH develops Maestro, an end-to-end service orchestrator, which allows for seamless deployment and management of services across geo-distributed and heterogeneous domains (including 5G). Maestro uses OpenZiti as a programmable integration fabric to enable connectivity in multi-domain and multi-tenant scenarios. |
| OSMIT GmbH | https://osmit.de/ | <img src="https://www.osmit.de/images/logo.svg" width="100px"> | OSMIT provides services for medium and large companies in the DACH region. We leverage the Zero Trust approach OpenZiti gives us to deliver our services in a secure manner to comply with data protection and privacy regulations (GDPR). |
| Actieve | https://actieve.com/ | <img src="https://www.actieve.com/Media/Images/Logo.png" width="100px"> | Actieve provides hosting for database and web servers around the world for a variety of enterprise and small business needs. Ziti gives us the ability to grant access to services and application without the worry of exposing the services to hackers. |
| Run Free | https://runfreeproject.com/ | <img src="https://shop.runfreeproject.com/assets/icons/apple-icon-144x144.png" width="100px"> | The Run Free Project provides a premium ecommerce experience for Run Speciaty stores. After a variety of intrusion attempts on the database and web services, Run Free implemented a Ziti only access policy for interconnecting store data and services. |
| Project Name | Project Link | Logo | How OpenZiti is used or why OpenZiti was chosen |
| ---------------------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| NetFoundry | https://nfconsole.io/signup | <img src="https://netfoundry.io/logos/Logo-Dark-Backgrounds.jpg" width="100px"> | NetFoundry SaaS provides management, orchestrations, support, and SLAs for OpenZiti networks. |
| Rockfield IT | https://rockfieldit.com/ | <img src="https://www.rockfieldit.com/wp-content/uploads/2024/03/adopters_openziti.png" width="100px"> | Rockfield IT delivers Managed IT Services with an integrated Zero Trust approach for internal and external applications. Utilizing OpenZiti, we've enabled seamless deployment of IoT, Kubernetes, SaltStack, and Modbus, alongside empowering our field technicians with live communication tools. This ensures secure, direct data relay to our HQ via the OpenZiti overlay network during on-site diagnostics. |
| HackBunker | https://www.hackbunker.com/ | <img src="https://irp.cdn-website.com/b429ad92/dms3rep/multi/hackbunker+logo+new.svg" width="100px"> | To open up a Zero Trust conversation in the C-Suite and Boardrooms of Blue-chip companies with a suite of products. |
| DeltaSecure GmbH | https://deltasecure.de/ | <img src="https://deltasecure.de/wp-content/uploads/2022/10/DeltaSecure-Logo-gross-hell.png.png" width="100px"> | To provide Managed Security Operations Center services for small and medium-sized enterprises. Ziti overlay forms the basis for secure data transmission of customer data and within the SOC infrastructure. |
| Resulticks | https://www.resulticks.com/ | <img src="https://www.resulticks.com/assets/platform/logos/resulticks-logo-blue.svg" width="100px"> | Resulticks Zero Trust API delivery network which forms the core of Resulticks' omnichannel marketing automation platform is built on OpenZiti to form a private dark mesh network. |
| KubeZT - Zero Trust Kubernetes | https://KubeZT.com/ | <img src="https://kubezt-public.s3-us-gov-east-1.amazonaws.com/github-org-logo.png" width="100px"> | KubeZT is an on-demand Kubernetes environment that enables developers to build and deploy highly secure applications for high-compliance organizations. |
| Analytics HQ | https://AnalyticsHQ.com/ | <img src="https://ahq-public.s3-us-gov-west-1.amazonaws.com/ahq-logo.png" width="100px"> | Analytics HQ is a next-generation unified platform built for modern data management and advanced analytics. |
| PITS Global Data Recovery Services | https://www.pitsdatarecovery.net/ | <img src="https://www.pitsdatarecovery.net/wp-content/uploads/2020/09/pits-logo.svg" width="100px"> | PITS Global Data Recovery Services is a data recovery company in the United States that offers services for recovering data from hard drives, SSDs, flash drives, RAID arrays and more. |
| KEOIC | http://www.keoic.com/ | <img src="https://static.wixstatic.com/media/300f00_ebca9ecefd8743eb82769e1d3079e55a~mv2.jpg" width="100px"> | KEO International Consultants is a multifaceted AEC firm with a presence across the Middle East and Europe. KEO uses the CloudZiti platform to facilitate zero-trust connections for users, devices, and applications throughout their worldwide network of branch offices and sites. |
| ChirpWireless | https://chirpwireless.io/ | <img src="https://docs.chirptoken.io/img/logo.svg" width="100px"> | Chirp is a project at the forefront of the DePIN (Decentralized physical infrastructure) movement, revolutionizing the world of wireless connectivity. It's a global telecommunications network that offers wireless internet and IoT connectivity for both residential and commercial use. OpenZiti overlay network is used for management of our LoRaWAN gateway miners ("Blackbirds") across multiple countries, allowing them to be dark. |
| GIGO Dev | https://gigo.dev/ | <img src="https://gigo.dev/logo192.png" width="100px"> | GIGO Dev is a learn-to-code platform that focuses on aligning learning with the real world of development. On GIGO you work in DevSpaces (Cloud Development Environments) capable of running nearly any system configuration needed for the challenge. We use OpenZiti to dynamically and securely expose network applications inside your DevSpace. Ziti provides the simplest, easiest, and most reliable system to securely route traffic into the local network of your DevSpace. |
| Underground Nexus | https://github.com/Underground-Ops/underground-nexus | <img src="https://raw.githubusercontent.com/Underground-Ops/underground-nexus/18d63a02aad41d8f540a044d5dd47f025d2b61a1/Graphics/SVG/cloud-underground-logo.svg" width="100px"> | Cloud Underground has chosen OpenZiti to integrate with our project called the Underground Nexus. OpenZiti provides our project with a unique way to maintain Zero Trust networking using it's overlay system to produce networks that don't require applications to be exposed to the public web - without the use of a VPN. |
| Ubitech | https://ubitech.eu/ | <img src="https://ubitech.eu/wp-content/uploads/logo.png" width="100px"> | UBITECH develops Maestro, an end-to-end service orchestrator, which allows for seamless deployment and management of services across geo-distributed and heterogeneous domains (including 5G). Maestro uses OpenZiti as a programmable integration fabric to enable connectivity in multi-domain and multi-tenant scenarios. |
| OSMIT GmbH | https://osmit.de/ | <img src="https://www.osmit.de/images/logo.svg" width="100px"> | OSMIT provides services for medium and large companies in the DACH region. We leverage the Zero Trust approach OpenZiti gives us to deliver our services in a secure manner to comply with data protection and privacy regulations (GDPR). |
| Actieve | https://actieve.com/ | <img src="https://www.actieve.com/Media/Images/Logo.png" width="100px"> | Actieve provides hosting for database and web servers around the world for a variety of enterprise and small business needs. Ziti gives us the ability to grant access to services and application without the worry of exposing the services to hackers. |
| Run Free | https://runfreeproject.com/ | <img src="https://shop.runfreeproject.com/assets/icons/apple-icon-144x144.png" width="100px"> | The Run Free Project provides a premium ecommerce experience for Run Speciaty stores. After a variety of intrusion attempts on the database and web services, Run Free implemented a Ziti only access policy for interconnecting store data and services. |
| grc4cisc | https://grc4ciso.com/ | <img src="https://grc4ciso.com/assets/img/logo_1.png" width="100px"> | grc4ciso is a SaaS platform that unifies the functionalities of a XDR + GRC + ZeroTrust. Zero Trust is based on OpenZiti, providing overlay network components necessary to integrate zero trust into small and medium-sized companies. |
+20
View File
@@ -1,3 +1,23 @@
# Release 0.34.2
## What's New
* The circuit id is now available in the SDK on the client and hosting side
* Requires 0.34.2+ routers
* Requests SDK support. Currently supported in the Go SDK 0.23.11+
* Bug fixes
## Component Updates and Bug Fixes
* github.com/openziti/edge-api: [v0.26.13 -> v0.26.14](https://github.com/openziti/edge-api/compare/v0.26.13...v0.26.14)
* github.com/openziti/sdk-golang: [v0.23.14 -> v0.23.15](https://github.com/openziti/sdk-golang/compare/v0.23.14...v0.23.15)
* github.com/openziti/secretstream: [v0.1.17 -> v0.1.18](https://github.com/openziti/secretstream/compare/v0.1.17...v0.1.18)
* [Issue #24](https://github.com/openziti/secretstream/issues/24) - Potential side channel issue
* [Issue #25](https://github.com/openziti/secretstream/issues/25) - Reads from crypto/rand not checked for errors
* github.com/openziti/ziti: [v0.34.1 -> v0.34.2](https://github.com/openziti/ziti/compare/v0.34.1...v0.34.2)
* [Issue #1831](https://github.com/openziti/ziti/issues/1831) - Circuit ID should be returned in the response to a Dial request
* [Issue #1873](https://github.com/openziti/ziti/issues/1873) - host.v1 health check time.Duration unconvertible
# Release 0.34.1
## What's New
File diff suppressed because it is too large Load Diff
+10
View File
@@ -175,6 +175,16 @@ message Controller {
bool isOnline = 6;
google.protobuf.Timestamp lastJoinedAt = 7;
map<string, TagValue> tags = 8;
map<string,ApiAddressList> apiAddresses = 9;
}
message ApiAddressList {
repeated ApiAddress addresses = 1;
}
message ApiAddress {
string Url = 1;
string Version = 2;
}
// Edge Routers
+4
View File
@@ -417,6 +417,10 @@ func (rdm *RouterDataModel) ApplyRevocationEvent(event *edge_ctrl_pb.DataState_E
rdm.sendEvent(event)
}
func (rdm *RouterDataModel) GetPublicKeys() map[string]*edge_ctrl_pb.DataState_PublicKey {
return rdm.PublicKeys.Items()
}
func (rdm *RouterDataModel) GetDataState() *edge_ctrl_pb.DataState {
var events []*edge_ctrl_pb.DataState_Event
+71 -1
View File
@@ -31,6 +31,7 @@ import (
"github.com/openziti/ziti/controller/zac"
"math/big"
"os"
"sync"
"sync/atomic"
"time"
@@ -85,6 +86,10 @@ type Controller struct {
metricsRegistry metrics.Registry
versionProvider versions.VersionProvider
eventDispatcher *events.Dispatcher
apiData map[string][]event.ApiAddress
apiDataBytes []byte
apiDataOnce sync.Once
}
func (c *Controller) GetPeerSigners() []*x509.Certificate {
@@ -154,6 +159,15 @@ func (c *Controller) GetRaftIndex() uint64 {
return c.raftController.Raft.LastIndex()
}
func (c *Controller) GetRaftInfo() (string, string, string) {
id := c.config.Id.Token
addr := c.raftController.Mesh.Addr().String()
version := c.GetVersionProvider().Version()
return string(addr), string(id), version
}
func (c *Controller) GetDb() boltz.Db {
return c.config.Db
}
@@ -338,7 +352,11 @@ func (c *Controller) Run() error {
panic(err)
}
go c.xweb.Run()
c.xweb.Run()
for _, helloHeader := range c.GetHelloHeaderProviders() {
helloHeader.Apply(headers)
}
// event handlers
if err := c.eventDispatcher.WireEventHandlers(c.getEventHandlerConfigs()); err != nil {
@@ -562,3 +580,55 @@ func (c *Controller) InitializeRaftFromBoltDb(sourceDbPath string) error {
return c.raftController.Dispatch(cmd)
}
// TODO: this functions is a temporary hack and should be provided by xweb
func getApiPath(binding string) string {
switch binding {
case "edge-client":
return "/edge/client/v1"
case "edge-management":
return "/edge/management/v1"
case "fabric":
return "/fabric/v1"
case "health-checks":
return "health-checks"
case "edge-oidc":
return "/oidc"
}
return ""
}
func (c *Controller) GetApiAddresses() (map[string][]event.ApiAddress, []byte) {
c.apiDataOnce.Do(func() {
xwebConfig := c.xweb.GetConfig()
apiData := map[string][]event.ApiAddress{}
for _, serverConfig := range xwebConfig.ServerConfigs {
for _, bindPoint := range serverConfig.BindPoints {
for _, api := range serverConfig.APIs {
apiData[api.Binding()] = append(apiData[api.Binding()], event.ApiAddress{
Url: "https://" + bindPoint.Address + getApiPath(api.Binding()), //TODO: temp till xweb support reporting API paths
Version: "v1", //TODO: temp till xweb supports reporting versions via api.Version()
})
}
}
}
c.apiData = apiData
c.apiDataBytes, _ = json.Marshal(apiData)
})
return c.apiData, c.apiDataBytes
}
func (c *Controller) GetHelloHeaderProviders() []mesh.HeaderProvider {
providerFunc := func(headers map[int32][]byte) {
_, apiDataBytes := c.GetApiAddresses()
headers[mesh.ApiAddressesHeader] = apiDataBytes
}
provider := mesh.HeaderProviderFunc(providerFunc)
return []mesh.HeaderProvider{provider}
}
+58 -9
View File
@@ -19,25 +19,35 @@ package db
import (
"github.com/openziti/storage/ast"
"github.com/openziti/storage/boltz"
"strconv"
"time"
)
const (
FieldControllerAddress = "address"
FieldControllerCertPem = "certPem"
FieldControllerFingerprint = "fingerprint"
FieldControllerIsOnline = "isOnline"
FieldControllerLastJoinedAt = "lastJoinedAt"
FieldControllerCtrlAddress = "ctrlAddress"
FieldControllerCertPem = "certPem"
FieldControllerFingerprint = "fingerprint"
FieldControllerIsOnline = "isOnline"
FieldControllerLastJoinedAt = "lastJoinedAt"
FieldControllerApiAddresses = "apiAddresses"
FieldControllerApiAddressVersion = "apiAddresses.version"
FieldControllerApiAddressUrl = "apiAddresses.url"
)
type Controller struct {
boltz.BaseExtEntity
Name string `json:"name"`
Address string `json:"address"`
CtrlAddress string `json:"address"`
CertPem string `json:"certPem"`
Fingerprint string `json:"fingerprint"`
IsOnline bool `json:"isOnline"`
LastJoinedAt *time.Time `json:"lastJoinedAt"`
ApiAddresses map[string][]ApiAddress
}
type ApiAddress struct {
Url string `json:"url"`
Version string `json:"version"`
}
func (entity *Controller) GetName() string {
@@ -75,7 +85,7 @@ func (store *controllerStoreImpl) initializeLocal() {
store.AddExtEntitySymbols()
store.indexName = store.addUniqueNameField()
store.AddSymbol(FieldControllerAddress, ast.NodeTypeString)
store.AddSymbol(FieldControllerCtrlAddress, ast.NodeTypeString)
store.AddSymbol(FieldControllerCertPem, ast.NodeTypeString)
store.AddSymbol(FieldControllerFingerprint, ast.NodeTypeString)
store.AddSymbol(FieldControllerIsOnline, ast.NodeTypeBool)
@@ -91,19 +101,58 @@ func (store *controllerStoreImpl) NewEntity() *Controller {
func (store *controllerStoreImpl) FillEntity(entity *Controller, bucket *boltz.TypedBucket) {
entity.LoadBaseValues(bucket)
entity.Name = bucket.GetStringOrError(FieldName)
entity.Address = bucket.GetStringWithDefault(FieldControllerAddress, "")
entity.CtrlAddress = bucket.GetStringWithDefault(FieldControllerCtrlAddress, "")
entity.CertPem = bucket.GetStringOrError(FieldControllerCertPem)
entity.Fingerprint = bucket.GetStringOrError(FieldControllerFingerprint)
entity.IsOnline = bucket.GetBoolWithDefault(FieldControllerIsOnline, false)
entity.LastJoinedAt = bucket.GetTime(FieldControllerLastJoinedAt)
entity.ApiAddresses = map[string][]ApiAddress{}
apiListBucket := bucket.GetBucket(FieldControllerApiAddresses)
if apiListBucket != nil {
apiListCursor := apiListBucket.Cursor()
for apiKey, _ := apiListCursor.First(); apiKey != nil; apiKey, _ = apiListCursor.Next() {
apiBucket := apiListBucket.GetBucket(string(apiKey))
if apiBucket != nil {
entity.ApiAddresses[string(apiKey)] = nil
instanceCursor := apiBucket.Cursor()
for instanceKey, _ := instanceCursor.First(); instanceKey != nil; instanceKey, _ = instanceCursor.Next() {
instance := apiBucket.GetBucket(string(instanceKey))
if instance != nil {
newInstance := ApiAddress{
Url: instance.GetStringWithDefault(FieldControllerApiAddressUrl, ""),
Version: instance.GetStringWithDefault(FieldControllerApiAddressVersion, ""),
}
entity.ApiAddresses[string(apiKey)] = append(entity.ApiAddresses[string(apiKey)], newInstance)
}
}
}
}
}
}
func (store *controllerStoreImpl) PersistEntity(entity *Controller, ctx *boltz.PersistContext) {
entity.SetBaseValues(ctx)
ctx.SetString(FieldName, entity.Name)
ctx.SetString(FieldControllerAddress, entity.Address)
ctx.SetString(FieldControllerCtrlAddress, entity.CtrlAddress)
ctx.SetString(FieldControllerCertPem, entity.CertPem)
ctx.SetString(FieldControllerFingerprint, entity.Fingerprint)
ctx.SetBool(FieldControllerIsOnline, entity.IsOnline)
ctx.SetTimeP(FieldControllerLastJoinedAt, entity.LastJoinedAt)
apiListBucket := ctx.Bucket.GetOrCreateBucket(FieldControllerApiAddresses)
for apiKey, apis := range entity.ApiAddresses {
apiBucket, _ := apiListBucket.EmptyBucket(apiKey)
for i, instance := range apis {
instanceBucket := apiBucket.GetOrCreateBucket(strconv.Itoa(i))
instanceBucket.SetString(FieldControllerApiAddressUrl, instance.Url, ctx.FieldChecker)
instanceBucket.SetString(FieldControllerApiAddressVersion, instance.Version, ctx.FieldChecker)
}
}
}
+12 -22
View File
@@ -314,6 +314,8 @@ type HostController interface {
GetEventDispatcher() event.Dispatcher
GetRaftIndex() uint64
GetPeerAddresses() []string
GetRaftInfo() (string, string, string)
GetApiAddresses() (map[string][]event.ApiAddress, []byte)
}
type Schemes struct {
@@ -830,29 +832,19 @@ func (ae *AppEnv) ControllersKeyFunc(token *jwt.Token) (interface{}, error) {
return nil, nil
}
return ae.GetControllerPublicKey(kid), nil
key := ae.GetControllerPublicKey(kid)
if key == nil {
return nil, fmt.Errorf("key for kid %s, not found", kid)
}
return key, nil
}
func (ae *AppEnv) GetControllerPublicKey(kid string) crypto.PublicKey {
serverTlsCert, serverKid, _ := ae.GetServerCert()
signers := ae.GetHostController().GetPeerSigners()
kids := map[string]crypto.PublicKey{
serverKid: serverTlsCert.Leaf.PublicKey,
}
for _, signer := range signers {
signerKid := fmt.Sprintf("%s", sha1.Sum(signer.Raw))
kids[signerKid] = signer.PublicKey
}
for curKid, publicKey := range kids {
if curKid == kid {
return publicKey
}
}
return nil
signers := ae.Broker.GetPublicKeys()
pfxlog.Logger().Info("looking for signer: " + kid)
return signers[kid]
}
func (ae *AppEnv) CreateRequestContext(rw http.ResponseWriter, r *http.Request) *response.RequestContext {
@@ -967,8 +959,6 @@ func (ae *AppEnv) SetServerCert(serverCert *tls.Certificate) {
signMethod := getJwtSigningMethod(serverCert)
kid := fmt.Sprintf("%x", sha1.Sum(serverCert.Certificate[0]))
ae.serverSigner = jwtsigner.New(signMethod, serverCert.PrivateKey, kid)
ae.Broker.routerSyncStrategy.AddPublicKey(ae.ServerCert)
}
func (ae *AppEnv) OidcIssuer() string {
+51 -6
View File
@@ -17,6 +17,8 @@
package env
import (
"crypto"
"crypto/x509"
"github.com/michaelquigley/pfxlog"
"github.com/openziti/channel/v2"
"github.com/openziti/storage/boltz"
@@ -25,6 +27,7 @@ import (
"github.com/openziti/ziti/controller/event"
"github.com/openziti/ziti/controller/network"
"go.etcd.io/bbolt"
"sync"
)
const (
@@ -57,6 +60,9 @@ type Broker struct {
apiSessionChunkSize int
routerMsgBufferSize int
routerSyncStrategy RouterSyncStrategy
publicKeyLock sync.Mutex
publicKeys map[string]crypto.PublicKey
}
func NewBroker(ae *AppEnv, synchronizer RouterSyncStrategy) *Broker {
@@ -73,13 +79,11 @@ func NewBroker(ae *AppEnv, synchronizer RouterSyncStrategy) *Broker {
broker.ae.GetStores().ApiSession.GetEventsEmitter().AddListener(db.EventFullyAuthenticated, broker.apiSessionFullyAuthenticated)
broker.ae.GetStores().ApiSessionCertificate.AddEntityEventListenerF(broker.apiSessionCertificateCreated, boltz.EntityCreatedAsync)
broker.ae.GetStores().ApiSessionCertificate.AddEntityEventListenerF(broker.apiSessionCertificateDeleted, boltz.EntityDeletedAsync)
broker.ae.GetStores().Controller.AddEntityEventListenerF(broker.controllerAdded, boltz.EntityCreated)
broker.ae.GetStores().Controller.AddEntityEventListenerF(broker.controllerAdded, boltz.EntityUpdated)
ae.HostController.GetNetwork().AddRouterPresenceHandler(broker)
ae.HostController.GetEventDispatcher().AddClusterEventHandler(broker)
ae.GetHostController().GetPeerSigners()
//updates controller store on leader, store update trigger strategy in all controllers
ae.HostController.GetEventDispatcher().AddClusterEventHandler(broker)
return broker
}
@@ -187,6 +191,47 @@ func (broker *Broker) Stop() {
broker.routerSyncStrategy.Stop()
}
func (broker *Broker) controllerAdded(controller *db.Controller) {
broker.routerSyncStrategy.PeerAdded(controller)
func (broker *Broker) GetPublicKeys() map[string]crypto.PublicKey {
broker.publicKeyLock.Lock()
defer broker.publicKeyLock.Unlock()
if broker.publicKeys == nil {
broker.publicKeys = map[string]crypto.PublicKey{}
}
for kid, pubKey := range broker.routerSyncStrategy.GetPublicKeys() {
//don't reprocess the same kid
if _, exists := broker.publicKeys[kid]; exists {
continue
}
log := pfxlog.Logger().WithField("format", pubKey.Format).WithField("kid", kid)
switch pubKey.Format {
case edge_ctrl_pb.DataState_PublicKey_X509CertDer:
cert, err := x509.ParseCertificate(pubKey.GetData())
if err != nil {
log.WithError(err).Error("error parsing x509 certificate DER")
continue
}
broker.publicKeys[kid] = cert.PublicKey
case edge_ctrl_pb.DataState_PublicKey_PKIXPublicKey:
pub, err := x509.ParsePKIXPublicKey(pubKey.GetData())
if err != nil {
log.WithError(err).Error("error parsing PKIX public key DER")
continue
}
broker.publicKeys[kid] = pub
default:
log.Error("unknown public key format")
}
}
result := map[string]crypto.PublicKey{}
for k, v := range broker.publicKeys {
result[k] = v
}
return result
}
+2 -5
View File
@@ -17,9 +17,9 @@
package env
import (
"crypto/tls"
"github.com/openziti/channel/v2"
"github.com/openziti/foundation/v2/versions"
"github.com/openziti/ziti/common/pb/edge_ctrl_pb"
"github.com/openziti/ziti/controller/db"
"github.com/openziti/ziti/controller/model"
"github.com/openziti/ziti/controller/network"
@@ -59,9 +59,9 @@ type RouterSyncStrategy interface {
Type() RouterSyncStrategyType
GetEdgeRouterState(id string) RouterStateValues
Stop()
GetPublicKeys() map[string]*edge_ctrl_pb.DataState_PublicKey
RouterConnectionHandler
RouterSynchronizerEventHandler
AddPublicKey(cert *tls.Certificate)
}
// RouterConnectionHandler is responsible for handling router connect/disconnect for synchronizing state.
@@ -78,10 +78,7 @@ type RouterSynchronizerEventHandler interface {
ApiSessionAdded(apiSession *db.ApiSession)
ApiSessionUpdated(apiSession *db.ApiSession, apiSessionCert *db.ApiSessionCertificate)
ApiSessionDeleted(apiSession *db.ApiSession)
SessionDeleted(session *db.Session)
PeerAdded(*db.Controller)
}
// RouterState provides a thread save mechanism to access and set router status information that may be influx
+10 -4
View File
@@ -37,10 +37,16 @@ const (
)
type ClusterPeer struct {
Id string `json:"id,omitempty"`
Addr string `json:"addr,omitempty"`
Version string `json:"version,omitempty"`
ServerCert []*x509.Certificate `json:"-"`
Id string `json:"id,omitempty"`
Addr string `json:"addr,omitempty"`
Version string `json:"version,omitempty"`
ServerCert []*x509.Certificate `json:"-"`
ApiAddresses map[string][]ApiAddress `json:"apiAddresses"`
}
type ApiAddress struct {
Url string `json:"url"`
Version string `json:"version"`
}
func (self *ClusterPeer) String() string {
@@ -18,6 +18,7 @@ package routes
import (
"github.com/openziti/edge-api/rest_model"
edgeController "github.com/openziti/ziti/controller"
"github.com/openziti/ziti/controller/env"
"github.com/openziti/ziti/controller/model"
"github.com/openziti/ziti/controller/response"
@@ -27,23 +28,56 @@ const EntityNameController = "controllers"
var ControllerLinkFactory = NewBasicLinkFactory(EntityNameController)
func MapControllerToRestEntity(_ *env.AppEnv, _ *response.RequestContext, Controller *model.Controller) (interface{}, error) {
return MapControllerToRestModel(Controller)
func MapControllerToManagementRestEntity(_ *env.AppEnv, _ *response.RequestContext, Controller *model.Controller) (interface{}, error) {
return MapControllerToManagementRestModel(Controller)
}
func MapControllerToRestModel(controller *model.Controller) (*rest_model.ControllerDetail, error) {
func MapControllerToClientRestEntity(_ *env.AppEnv, _ *response.RequestContext, Controller *model.Controller) (interface{}, error) {
return MapControllerToClientRestModel(Controller)
}
func MapControllerToManagementRestModel(controller *model.Controller) (*rest_model.ControllerDetail, error) {
ret := &rest_model.ControllerDetail{
BaseEntity: BaseEntityToRestModel(controller, ControllerLinkFactory),
Name: &controller.Name,
Address: &controller.Address,
CertPem: &controller.CertPem,
Fingerprint: &controller.Fingerprint,
IsOnline: &controller.IsOnline,
BaseEntity: BaseEntityToRestModel(controller, ControllerLinkFactory),
Name: &controller.Name,
CtrlAddress: &controller.CtrlAddress,
APIAddresses: rest_model.APIAddressList{},
CertPem: &controller.CertPem,
Fingerprint: &controller.Fingerprint,
IsOnline: &controller.IsOnline,
}
if controller.LastJoinedAt != nil {
ret.LastJoinedAt = toStrFmtDateTimeP(*controller.LastJoinedAt)
}
for apiKey, instances := range controller.ApiAddresses {
ret.APIAddresses[apiKey] = rest_model.APIAddressArray{}
for _, instance := range instances {
ret.APIAddresses[apiKey] = append(ret.APIAddresses[apiKey], &rest_model.APIAddress{
URL: instance.Url,
Version: instance.Version,
})
}
}
return ret, nil
}
func MapControllerToClientRestModel(controller *model.Controller) (*rest_model.ControllerDetail, error) {
ret, err := MapControllerToManagementRestModel(controller)
if err != nil {
return nil, err
}
ret.CtrlAddress = nil
for apiKey := range ret.APIAddresses {
if apiKey != edgeController.ClientApiBinding && apiKey != edgeController.OidcApiBinding {
delete(ret.APIAddresses, apiKey)
}
}
return ret, nil
}
@@ -43,14 +43,18 @@ func NewControllerRouter() *ControllerRouter {
func (r *ControllerRouter) Register(ae *env.AppEnv) {
ae.ManagementApi.ControllersListControllersHandler = controllersMan.ListControllersHandlerFunc(func(params controllersMan.ListControllersParams, _ interface{}) middleware.Responder {
return ae.IsAllowed(r.List, params.HTTPRequest, "", "", permissions.IsAdmin())
return ae.IsAllowed(r.ListManagement, params.HTTPRequest, "", "", permissions.IsAuthenticated())
})
ae.ClientApi.ControllersListControllersHandler = controllersClient.ListControllersHandlerFunc(func(params controllersClient.ListControllersParams, _ interface{}) middleware.Responder {
return ae.IsAllowed(r.List, params.HTTPRequest, "", "", permissions.IsAdmin())
return ae.IsAllowed(r.ListClient, params.HTTPRequest, "", "", permissions.IsAuthenticated())
})
}
func (r *ControllerRouter) List(ae *env.AppEnv, rc *response.RequestContext) {
ListWithHandler[*model.Controller](ae, rc, ae.Managers.Controller, MapControllerToRestEntity)
func (r *ControllerRouter) ListManagement(ae *env.AppEnv, rc *response.RequestContext) {
ListWithHandler[*model.Controller](ae, rc, ae.Managers.Controller, MapControllerToManagementRestEntity)
}
func (r *ControllerRouter) ListClient(ae *env.AppEnv, rc *response.RequestContext) {
ListWithHandler[*model.Controller](ae, rc, ae.Managers.Controller, MapControllerToClientRestEntity)
}
+105 -12
View File
@@ -17,6 +17,7 @@
package model
import (
"crypto/x509"
"github.com/michaelquigley/pfxlog"
nfpem "github.com/openziti/foundation/v2/pem"
"github.com/openziti/foundation/v2/stringz"
@@ -117,11 +118,22 @@ func (self *ControllerManager) Marshall(entity *Controller) ([]byte, error) {
msg := &edge_cmd_pb.Controller{
Id: entity.Id,
Name: entity.Name,
Address: entity.Address,
Address: entity.CtrlAddress,
CertPem: entity.CertPem,
Fingerprint: entity.Fingerprint,
IsOnline: entity.IsOnline,
LastJoinedAt: timePtrToPb(entity.LastJoinedAt),
ApiAddresses: map[string]*edge_cmd_pb.ApiAddressList{},
}
for apiKey, instances := range entity.ApiAddresses {
msg.ApiAddresses[apiKey] = &edge_cmd_pb.ApiAddressList{}
for _, instance := range instances {
msg.ApiAddresses[apiKey].Addresses = append(msg.ApiAddresses[apiKey].Addresses, &edge_cmd_pb.ApiAddress{
Url: instance.Url,
Version: instance.Version,
})
}
}
return proto.Marshal(msg)
@@ -134,18 +146,57 @@ func (self *ControllerManager) Unmarshall(bytes []byte) (*Controller, error) {
return nil, err
}
return &Controller{
controller := &Controller{
BaseEntity: models.BaseEntity{
Id: msg.Id,
Tags: edge_cmd_pb.DecodeTags(msg.Tags),
},
Name: msg.Name,
Address: msg.Address,
CtrlAddress: msg.Address,
CertPem: msg.CertPem,
Fingerprint: msg.Fingerprint,
IsOnline: msg.IsOnline,
LastJoinedAt: pbTimeToTimePtr(msg.LastJoinedAt),
}, nil
ApiAddresses: map[string][]ApiAddress{},
}
for apiKey, instanceList := range msg.ApiAddresses {
controller.ApiAddresses[apiKey] = nil
if instanceList != nil {
for _, instance := range instanceList.Addresses {
controller.ApiAddresses[apiKey] = append(controller.ApiAddresses[apiKey], ApiAddress{
Url: instance.Url,
Version: instance.Version,
})
}
}
}
return controller, nil
}
func (self *ControllerManager) getCurrentAsClusterPeer() *event.ClusterPeer {
addr, id, version := self.env.GetHostController().GetRaftInfo()
tlsConfig, _, _ := self.env.GetServerCert()
var leaderCerts []*x509.Certificate
for _, certBytes := range tlsConfig.Certificate {
cert, err := x509.ParseCertificate(certBytes)
if err == nil {
leaderCerts = append(leaderCerts, cert)
}
}
apiAddresses, _ := self.env.GetHostController().GetApiAddresses()
return &event.ClusterPeer{
Id: id,
Addr: addr,
Version: version,
ServerCert: leaderCerts,
ApiAddresses: apiAddresses,
}
}
func (self *ControllerManager) PeersConnected(peers []*event.ClusterPeer) {
@@ -165,27 +216,58 @@ func (self *ControllerManager) PeersConnected(peers []*event.ClusterPeer) {
}
connectFields := fields.UpdatedFieldsMap{
db.FieldControllerLastJoinedAt: struct{}{},
db.FieldControllerCertPem: struct{}{},
db.FieldControllerFingerprint: struct{}{},
db.FieldControllerIsOnline: struct{}{},
db.FieldControllerAddress: struct{}{},
db.FieldControllerLastJoinedAt: struct{}{},
db.FieldControllerCertPem: struct{}{},
db.FieldControllerFingerprint: struct{}{},
db.FieldControllerIsOnline: struct{}{},
db.FieldControllerCtrlAddress: struct{}{},
db.FieldControllerApiAddresses: struct{}{},
db.FieldControllerApiAddressUrl: struct{}{},
db.FieldControllerApiAddressVersion: struct{}{},
}
now := time.Now()
selfAsPeer := self.getCurrentAsClusterPeer()
peerFingerprints := ""
for _, peer := range peers {
fingerprint := nfpem.FingerprintFromCertificate(peer.ServerCert[0])
if peerFingerprints == "" {
peerFingerprints = fingerprint
} else {
peerFingerprints = peerFingerprints + ", " + fingerprint
}
}
pfxlog.Logger().Infof("acting as leader, updating controllers with peers, self: %s, peers: %s", nfpem.FingerprintFromCertificate(selfAsPeer.ServerCert[0]), peerFingerprints)
// always as this controller as a "peer" to add or update on the controller list
peers = append(peers, selfAsPeer)
for _, peer := range peers {
if stringz.Contains(controllerIds, peer.Id) {
existing, err := self.Read(peer.Id)
if err != nil {
pfxlog.Logger().WithError(err).Error("could not handle new peer(s) connection, existing controller could not be read")
continue
}
existing.Address = peer.Addr
existing.CtrlAddress = peer.Addr
existing.IsOnline = true
existing.LastJoinedAt = &now
existing.ApiAddresses = map[string][]ApiAddress{}
for apiKey, instances := range peer.ApiAddresses {
existing.ApiAddresses[apiKey] = nil
for _, instance := range instances {
existing.ApiAddresses[apiKey] = append(existing.ApiAddresses[apiKey], ApiAddress{
Url: instance.Url,
Version: instance.Version,
})
}
}
if len(peer.ServerCert) > 0 {
existing.CertPem = nfpem.EncodeToString(peer.ServerCert[0])
@@ -205,11 +287,22 @@ func (self *ControllerManager) PeersConnected(peers []*event.ClusterPeer) {
BaseEntity: models.BaseEntity{
Id: peer.Id,
},
Address: peer.Addr,
CtrlAddress: peer.Addr,
IsOnline: true,
LastJoinedAt: &now,
}
for apiKey, instances := range peer.ApiAddresses {
newController.ApiAddresses[apiKey] = nil
for _, instance := range instances {
newController.ApiAddresses[apiKey] = append(newController.ApiAddresses[apiKey], ApiAddress{
Url: instance.Url,
Version: instance.Version,
})
}
}
newController.Name = peer.ServerCert[0].Subject.CommonName
newController.CertPem = nfpem.EncodeToString(peer.ServerCert[0])
newController.Fingerprint = nfpem.FingerprintFromCertificate(peer.ServerCert[0])
+31 -3
View File
@@ -27,22 +27,39 @@ import (
type Controller struct {
models.BaseEntity
Name string
Address string
CtrlAddress string
CertPem string
Fingerprint string
IsOnline bool
LastJoinedAt *time.Time
ApiAddresses map[string][]ApiAddress
}
type ApiAddress struct {
Url string `json:"url"`
Version string `json:"version"`
}
func (entity *Controller) toBoltEntity(tx *bbolt.Tx, env Env) (*db.Controller, error) {
boltEntity := &db.Controller{
BaseExtEntity: *boltz.NewExtEntity(entity.Id, entity.Tags),
Name: entity.Name,
Address: entity.Address,
CtrlAddress: entity.CtrlAddress,
CertPem: entity.CertPem,
Fingerprint: entity.Fingerprint,
IsOnline: entity.IsOnline,
LastJoinedAt: entity.LastJoinedAt,
ApiAddresses: map[string][]db.ApiAddress{},
}
for apiKey, instances := range entity.ApiAddresses {
boltEntity.ApiAddresses[apiKey] = nil
for _, instance := range instances {
boltEntity.ApiAddresses[apiKey] = append(boltEntity.ApiAddresses[apiKey], db.ApiAddress{
Url: instance.Url,
Version: instance.Version,
})
}
}
return boltEntity, nil
@@ -59,11 +76,22 @@ func (entity *Controller) toBoltEntityForUpdate(tx *bbolt.Tx, env Env, _ boltz.F
func (entity *Controller) fillFrom(env Env, tx *bbolt.Tx, boltController *db.Controller) error {
entity.FillCommon(boltController)
entity.Name = boltController.Name
entity.Address = boltController.Address
entity.CtrlAddress = boltController.CtrlAddress
entity.CertPem = boltController.CertPem
entity.Fingerprint = boltController.Fingerprint
entity.IsOnline = boltController.IsOnline
entity.LastJoinedAt = boltController.LastJoinedAt
entity.ApiAddresses = map[string][]ApiAddress{}
for apiKey, instances := range boltController.ApiAddresses {
entity.ApiAddresses[apiKey] = nil
for _, instance := range instances {
entity.ApiAddresses[apiKey] = append(entity.ApiAddresses[apiKey], ApiAddress{
Url: instance.Url,
Version: instance.Version,
})
}
}
return nil
}
+3
View File
@@ -26,6 +26,7 @@ import (
"github.com/openziti/ziti/common/cert"
"github.com/openziti/ziti/controller/config"
"github.com/openziti/ziti/controller/db"
"github.com/openziti/ziti/controller/event"
"github.com/openziti/ziti/controller/jwtsigner"
"github.com/openziti/ziti/controller/network"
"github.com/xeipuuv/gojsonschema"
@@ -67,6 +68,8 @@ type HostController interface {
Identity() identity.Identity
GetPeerSigners() []*x509.Certificate
GetRaftIndex() uint64
GetRaftInfo() (string, string, string)
GetApiAddresses() (map[string][]event.ApiAddress, []byte)
}
type Schemas interface {
+9 -1
View File
@@ -50,6 +50,14 @@ type testHostController struct {
ctx *TestContext
}
func (self *testHostController) GetApiAddresses() (map[string][]event.ApiAddress, []byte) {
return nil, nil
}
func (self *testHostController) GetRaftInfo() (string, string, string) {
return "testaddr", "testid", "testversion"
}
func (self *testHostController) GetRaftIndex() uint64 {
return 0
}
@@ -171,7 +179,7 @@ func (ctx *TestContext) GetApiServerCsrSigner() cert.Signer {
}
func (ctx *TestContext) GetControlClientCsrSigner() cert.Signer {
panic("implement me")
return nil
}
func (ctx *TestContext) GetHostController() HostController {
+52 -14
View File
@@ -18,6 +18,7 @@ package mesh
import (
"crypto/x509"
"encoding/json"
"fmt"
"github.com/openziti/foundation/v2/concurrenz"
"github.com/openziti/foundation/v2/versions"
@@ -41,9 +42,10 @@ import (
const (
PeerAddrHeader = 11
RaftConnectType = 2048
RaftDataType = 2049
SigningCertHeader = 2050
RaftConnectType = 2048
RaftDataType = 2049
SigningCertHeader = 2050
ApiAddressesHeader = 2051
ChannelTypeMesh = "ctrl.mesh"
)
@@ -56,6 +58,7 @@ type Peer struct {
RaftConn *raftPeerConn
Version *versions.VersionInfo
SigningCerts []*x509.Certificate
ApiAddresses map[string][]event.ApiAddress
}
func (self *Peer) HandleClose(channel.Channel) {
@@ -143,7 +146,7 @@ type Mesh interface {
Init(bindHandler channel.BindHandler)
}
func New(env Env, raftAddr raft.ServerAddress) Mesh {
func New(env Env, raftAddr raft.ServerAddress, helloHeaderProviders []HeaderProvider) Mesh {
versionEncoded, err := env.GetVersionProvider().EncoderDecoder().Encode(env.GetVersionProvider().AsVersionInfo())
if err != nil {
panic(err)
@@ -156,12 +159,13 @@ func New(env Env, raftAddr raft.ServerAddress) Mesh {
network: "mesh",
addr: string(raftAddr),
},
Peers: map[string]*Peer{},
closeNotify: make(chan struct{}),
raftAccepts: make(chan net.Conn),
version: env.GetVersionProvider(),
versionEncoded: versionEncoded,
eventDispatcher: env.GetEventDispatcher(),
Peers: map[string]*Peer{},
closeNotify: make(chan struct{}),
raftAccepts: make(chan net.Conn),
version: env.GetVersionProvider(),
versionEncoded: versionEncoded,
eventDispatcher: env.GetEventDispatcher(),
helloHeaderProviders: helloHeaderProviders,
}
}
@@ -180,6 +184,7 @@ type impl struct {
readonly atomic.Bool
clusterStateHandlers concurrenz.CopyOnWriteSlice[func(state ClusterState)]
eventDispatcher event.Dispatcher
helloHeaderProviders []HeaderProvider
}
func (self *impl) RegisterClusterStateHandler(f func(state ClusterState)) {
@@ -257,6 +262,10 @@ func (self *impl) GetOrConnectPeer(address string, timeout time.Duration) (*Peer
SigningCertHeader: serverCert,
}
for _, headerProvider := range self.helloHeaderProviders {
headerProvider.Apply(headers)
}
dialer := channel.NewClassicDialer(self.id, addr, headers)
dialOptions := channel.DefaultOptions()
dialOptions.ConnectOptions.ConnectTimeout = timeout
@@ -293,6 +302,13 @@ func (self *impl) GetOrConnectPeer(address string, timeout time.Duration) (*Peer
return errors.Wrap(err, "can't decode version from returned from peer")
}
if apiAddressBytes, found := peer.Channel.Underlay().Headers()[ApiAddressesHeader]; found {
err := json.Unmarshal(apiAddressBytes, &peer.ApiAddresses)
if err != nil {
pfxlog.Logger().WithError(err).Error("could not unmarshal api address header")
}
}
peer.Version = versionInfo
peer.RaftConn = newRaftPeerConn(peer, self.netAddr)
peer.SigningCerts = []*x509.Certificate{underlay.Certificates()[0]}
@@ -331,6 +347,10 @@ func (self *impl) GetPeerInfo(address string, timeout time.Duration) (raft.Serve
PeerAddrHeader: []byte(self.raftAddr),
}
for _, headerProvider := range self.helloHeaderProviders {
headerProvider.Apply(headers)
}
dialer := channel.NewClassicDialer(self.id, addr, headers)
dialOptions := channel.DefaultOptions()
dialOptions.ConnectOptions.ConnectTimeout = timeout
@@ -404,10 +424,11 @@ func (self *impl) PeerConnected(peer *Peer) error {
evt := event.NewClusterEvent(event.ClusterPeerConnected)
evt.Peers = append(evt.Peers, &event.ClusterPeer{
Id: string(peer.Id),
Addr: peer.Address,
Version: peer.Version.Version,
ServerCert: peer.SigningCerts,
Id: string(peer.Id),
Addr: peer.Address,
Version: peer.Version.Version,
ServerCert: peer.SigningCerts,
ApiAddresses: peer.ApiAddresses,
})
self.eventDispatcher.AcceptClusterEvent(evt)
@@ -522,6 +543,13 @@ func (self *impl) AcceptUnderlay(underlay channel.Underlay) error {
}
}
apiAddressesHeader, found := ch.Underlay().Headers()[ApiAddressesHeader]
if found {
if err := json.Unmarshal(apiAddressesHeader, &peer.ApiAddresses); err != nil {
pfxlog.Logger().WithError(err).Error("could not parse peer api addresses header")
}
}
peer.Version = versionInfo
peer.RaftConn = newRaftPeerConn(peer, self.netAddr)
@@ -560,3 +588,13 @@ func (self *impl) GetPeers() map[string]*Peer {
func (self *impl) IsReadOnly() bool {
return self.readonly.Load()
}
type HeaderProvider interface {
Apply(map[int32][]byte)
}
type HeaderProviderFunc func(map[int32][]byte)
func (self HeaderProviderFunc) Apply(headers map[int32][]byte) {
self(headers)
}
+4 -1
View File
@@ -197,6 +197,7 @@ type Env interface {
GetMetricsRegistry() metrics.Registry
GetEventDispatcher() event.Dispatcher
GetCloseNotify() <-chan struct{}
GetHelloHeaderProviders() []mesh.HeaderProvider
}
func NewController(env Env, migrationMgr MigrationManager) *Controller {
@@ -540,7 +541,9 @@ func (self *Controller) Init() error {
return err
}
self.Mesh = mesh.New(self.env, localAddr)
helloHeaderProviders := self.env.GetHelloHeaderProviders()
self.Mesh = mesh.New(self.env, localAddr, helloHeaderProviders)
self.Mesh.RegisterClusterStateHandler(func(state mesh.ClusterState) {
obs := raft.Observation{
Raft: self.Raft,
+28 -21
View File
@@ -113,6 +113,7 @@ type InstantStrategy struct {
serviceHandler *constraintToIndexedEvents[*db.EdgeService]
caHandler *constraintToIndexedEvents[*db.Ca]
revocationHandler *constraintToIndexedEvents[*db.Revocation]
controllerHandler *constraintToIndexedEvents[*db.Controller]
}
func (strategy *InstantStrategy) AddPublicKey(cert *tls.Certificate) {
@@ -202,6 +203,12 @@ func (strategy *InstantStrategy) Initialize(logSize uint64, bufferSize uint) err
}
strategy.ae.GetStores().Revocation.AddEntityConstraint(strategy.revocationHandler)
strategy.controllerHandler = &constraintToIndexedEvents[*db.Controller]{
indexProvider: strategy.indexProvider,
createHandler: strategy.ControllerCreate,
updateHandler: strategy.ControllerUpdate,
}
return nil
}
@@ -829,14 +836,22 @@ func (strategy *InstantStrategy) BuildServicePolicies(tx *bbolt.Tx) error {
}
func (strategy *InstantStrategy) BuildPublicKeys(tx *bbolt.Tx) error {
for _, x509Cert := range strategy.ae.HostController.GetPeerSigners() {
publicKey := newPublicKey(x509Cert.Raw, edge_ctrl_pb.DataState_PublicKey_X509CertDer, []edge_ctrl_pb.DataState_PublicKey_Usage{edge_ctrl_pb.DataState_PublicKey_ClientX509CertValidation, edge_ctrl_pb.DataState_PublicKey_JWTValidation})
newModel := &edge_ctrl_pb.DataState_Event_PublicKey{PublicKey: publicKey}
for cursor := strategy.ae.GetStores().Controller.IterateIds(tx, ast.BoolNodeTrue); cursor.IsValid(); cursor.Next() {
currentBytes := cursor.Current()
currentId := string(currentBytes)
storeModel, err := strategy.ae.GetStores().Controller.LoadById(tx, currentId)
if err != nil {
return err
}
certs := nfPem.PemStringToCertificates(storeModel.CertPem)
newModel := &edge_ctrl_pb.DataState_Event_PublicKey{PublicKey: newPublicKey(certs[0].Raw, edge_ctrl_pb.DataState_PublicKey_X509CertDer, []edge_ctrl_pb.DataState_PublicKey_Usage{edge_ctrl_pb.DataState_PublicKey_JWTValidation, edge_ctrl_pb.DataState_PublicKey_ClientX509CertValidation})}
newEvent := &edge_ctrl_pb.DataState_Event{
Action: edge_ctrl_pb.DataState_Create,
Model: newModel,
}
strategy.HandlePublicKeyEvent(newEvent, newModel)
}
@@ -1244,24 +1259,16 @@ func (strategy *InstantStrategy) PostureCheckDelete(index uint64, postureCheck *
strategy.handlePostureCheck(index, edge_ctrl_pb.DataState_Delete, postureCheck)
}
func (strategy *InstantStrategy) PeerAdded(peer *db.Controller) {
if len(peer.CertPem) > 0 {
certs := nfPem.PemBytesToCertificates([]byte(peer.CertPem))
func (strategy *InstantStrategy) ControllerCreate(index uint64, controller *db.Controller) {
certs := nfPem.PemStringToCertificates(controller.CertPem)
cert := certs[0]
strategy.handlePublicKey(index, edge_ctrl_pb.DataState_Create, newPublicKey(cert.Raw, edge_ctrl_pb.DataState_PublicKey_X509CertDer, []edge_ctrl_pb.DataState_PublicKey_Usage{edge_ctrl_pb.DataState_PublicKey_ClientX509CertValidation, edge_ctrl_pb.DataState_PublicKey_JWTValidation}))
}
if len(certs) > 0 {
strategy.Apply(&edge_ctrl_pb.DataState_Event{
IsSynthetic: true,
Action: edge_ctrl_pb.DataState_Create,
Model: &edge_ctrl_pb.DataState_Event_PublicKey{
PublicKey: newPublicKey(certs[0].Raw, edge_ctrl_pb.DataState_PublicKey_X509CertDer, []edge_ctrl_pb.DataState_PublicKey_Usage{edge_ctrl_pb.DataState_PublicKey_ClientX509CertValidation, edge_ctrl_pb.DataState_PublicKey_JWTValidation}),
},
})
} else {
pfxlog.Logger().Warn("peer added event, certificate pem did not parse to at least one certificate")
}
} else {
pfxlog.Logger().Warn("peer added event without certificate pem")
}
func (strategy *InstantStrategy) ControllerUpdate(index uint64, controller *db.Controller) {
certs := nfPem.PemStringToCertificates(controller.CertPem)
cert := certs[0]
strategy.handlePublicKey(index, edge_ctrl_pb.DataState_Create, newPublicKey(cert.Raw, edge_ctrl_pb.DataState_PublicKey_X509CertDer, []edge_ctrl_pb.DataState_PublicKey_Usage{edge_ctrl_pb.DataState_PublicKey_ClientX509CertValidation, edge_ctrl_pb.DataState_PublicKey_JWTValidation}))
}
func (strategy *InstantStrategy) CaCreate(index uint64, ca *db.Ca) {
+5
View File
@@ -0,0 +1,5 @@
er1.*
er1/
er2.*
er2/
endpoints
+5
View File
@@ -51,3 +51,8 @@ web:
- binding: edge-management
- binding: edge-client
- binding: edge-oidc
options:
redirectURIs:
- "http://localhost:*/auth/callback"
- "http://127.0.0.1:*/auth/callback"
- "https://oauth.pstmn.io/v1/callback"
+5
View File
@@ -40,3 +40,8 @@ web:
- binding: edge-management
- binding: edge-client
- binding: edge-oidc
options:
redirectURIs:
- "http://localhost:*/auth/callback"
- "http://127.0.0.1:*/auth/callback"
- "https://oauth.pstmn.io/v1/callback"
+5
View File
@@ -40,3 +40,8 @@ web:
- binding: edge-management
- binding: edge-client
- binding: edge-oidc
options:
redirectURIs:
- "http://localhost:*/auth/callback"
- "http://127.0.0.1:*/auth/callback"
- "https://oauth.pstmn.io/v1/callback"
+7 -8
View File
@@ -8,7 +8,7 @@ require (
github.com/Jeffail/gabs/v2 v2.7.0
github.com/MakeNowJust/heredoc v1.0.0
github.com/blang/semver v3.5.1+incompatible
github.com/cenkalti/backoff/v4 v4.2.1
github.com/cenkalti/backoff/v4 v4.3.0
github.com/coreos/go-iptables v0.7.0
github.com/dgryski/dgoogauth v0.0.0-20190221195224-5a805980a5f3
github.com/dineshappavoo/basex v0.0.0-20170425072625-481a6f6dc663
@@ -49,14 +49,14 @@ require (
github.com/natefinch/lumberjack v2.0.0+incompatible
github.com/openziti/agent v1.0.16
github.com/openziti/channel/v2 v2.0.122
github.com/openziti/edge-api v0.26.13
github.com/openziti/edge-api v0.26.14
github.com/openziti/foundation/v2 v2.0.40
github.com/openziti/identity v1.0.73
github.com/openziti/jwks v1.0.3
github.com/openziti/metrics v1.2.48
github.com/openziti/runzmd v1.0.41
github.com/openziti/sdk-golang v0.23.14
github.com/openziti/secretstream v0.1.17
github.com/openziti/sdk-golang v0.23.15
github.com/openziti/secretstream v0.1.18
github.com/openziti/storage v0.2.33
github.com/openziti/transport/v2 v2.0.125
github.com/openziti/x509-claims v1.0.3
@@ -67,7 +67,7 @@ require (
github.com/rabbitmq/amqp091-go v1.8.1
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475
github.com/russross/blackfriday v1.6.0
github.com/shirou/gopsutil/v3 v3.24.2
github.com/shirou/gopsutil/v3 v3.24.3
github.com/sirupsen/logrus v1.9.3
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/spf13/cobra v1.8.0
@@ -82,7 +82,7 @@ require (
golang.org/x/crypto v0.21.0
golang.org/x/net v0.22.0
golang.org/x/sync v0.6.0
golang.org/x/sys v0.18.0
golang.org/x/sys v0.19.0
golang.org/x/text v0.14.0
google.golang.org/protobuf v1.33.0
gopkg.in/AlecAivazis/survey.v1 v1.8.7
@@ -184,10 +184,9 @@ require (
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
golang.org/x/image v0.13.0 // indirect
golang.org/x/mod v0.15.0 // indirect
golang.org/x/oauth2 v0.18.0 // indirect
golang.org/x/oauth2 v0.19.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/tools v0.18.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
nhooyr.io/websocket v1.8.10 // indirect
+14 -16
View File
@@ -107,8 +107,8 @@ github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBT
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/c-bata/go-prompt v0.2.6 h1:POP+nrHE+DfLYx370bedwNhsqmpCUynWPxuHi0C5vZI=
github.com/c-bata/go-prompt v0.2.6/go.mod h1:/LMAke8wD2FsNu9EXNdHxNLbd9MedkPnCdfpU9wwHfY=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
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 v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -570,8 +570,8 @@ github.com/openziti/channel/v2 v2.0.122 h1:MPALuLUuTsW2QJzaoRkrP/wGqhIeWtSsrnxt2
github.com/openziti/channel/v2 v2.0.122/go.mod h1:n4r/pWTFYJy98hEtf4ATYVHU70OePjoM8JJzrIvXvZg=
github.com/openziti/dilithium v0.3.3 h1:PLgQ6PMNLSTzCFbX/h98cmudgz/cU6TmjdSv5NAPD8k=
github.com/openziti/dilithium v0.3.3/go.mod h1:vsCjI2AU/hon9e+dLhUFbCNGesJDj2ASgkySOcpmvjo=
github.com/openziti/edge-api v0.26.13 h1:lWAHu04nk7a0AEnJBjmwijUIEE+NvNAiOcdg11dxbIY=
github.com/openziti/edge-api v0.26.13/go.mod h1:aTRqB9J/6ISbw9+YWjzD0tvWAXY98m8yWcbiGNqAQTU=
github.com/openziti/edge-api v0.26.14 h1:BpxKavDVdykOY7GSdKXi7klv9Im4vw7bTMujz3wFE1Q=
github.com/openziti/edge-api v0.26.14/go.mod h1:aTRqB9J/6ISbw9+YWjzD0tvWAXY98m8yWcbiGNqAQTU=
github.com/openziti/foundation/v2 v2.0.40 h1:8oXL77egZjnQuKuxPTHiBOh+X/I2mSJefIbnLSv8rFI=
github.com/openziti/foundation/v2 v2.0.40/go.mod h1:38RikdtjvzDUALm3jT3PSOrU0bHCleRty6bHGdfFyUI=
github.com/openziti/identity v1.0.73 h1:F1iF/rDQYfDIv4ktqBYwK/0C5Ra/7y92Z5Umrw4c4fk=
@@ -582,10 +582,10 @@ github.com/openziti/metrics v1.2.48 h1:bDUcWSTWM4vXh4YU8z953Q/vtlUjtH+pSaQviKzB5
github.com/openziti/metrics v1.2.48/go.mod h1:rLFoXigAFb5clCDqe/RlvFFjlaTr9Li7iEn3OxInmb0=
github.com/openziti/runzmd v1.0.41 h1:Iuwe91Lzq63ux2R6+VIWEvcEKhpKkPb1QVNwrJHOuDA=
github.com/openziti/runzmd v1.0.41/go.mod h1:T79oGLLJNnAhHzcfnlrOR39S2XGkzwYZLZh62xee0wk=
github.com/openziti/sdk-golang v0.23.14 h1:usGFwrc7jcGkvas5TVLWQgdWs/FBUZrORb6jV+KM2eY=
github.com/openziti/sdk-golang v0.23.14/go.mod h1:mM7C6QMcEZwVhBLwmrq8PtBMyBbXXoKr186CDpTx5rI=
github.com/openziti/secretstream v0.1.17 h1:bcaPGGpUl0+3GzfQkshKh5slUE7QDXxFq3vyDQgHkCA=
github.com/openziti/secretstream v0.1.17/go.mod h1:gosi8ohW+dAHhz1h/MjZEcEVWO0jisWqWjEjmx7oAEs=
github.com/openziti/sdk-golang v0.23.15 h1:+h+zin2CB6nP8e2Sqi2Jxo4Sbo3wTp8PIfh7QNm4lPA=
github.com/openziti/sdk-golang v0.23.15/go.mod h1:aYvN+PCUV2AHPcbgcG1Khgso5TbmNaLMke0ByshU4Hs=
github.com/openziti/secretstream v0.1.18 h1:bMHI4ez6pVSGFzHCHHn6imkaCYqd3o9Oa8gDObf8icI=
github.com/openziti/secretstream v0.1.18/go.mod h1:gosi8ohW+dAHhz1h/MjZEcEVWO0jisWqWjEjmx7oAEs=
github.com/openziti/storage v0.2.33 h1:15WKxJ0J1GCNOMmOkoosjoxKN2Hrm4p3g8p9WAiMS9Y=
github.com/openziti/storage v0.2.33/go.mod h1:AbE5KkTVlXVFHRqpc7Ug3eFpNOc1HFBFwNIYn8Rtp+s=
github.com/openziti/transport/v2 v2.0.125 h1:6kDfabGFIE2+UPyvJVtfI43CNKcMwNOrCRX602CbDU4=
@@ -674,8 +674,8 @@ 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/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shirou/gopsutil/v3 v3.24.2 h1:kcR0erMbLg5/3LcInpw0X/rrPSqq4CDPyI6A6ZRC18Y=
github.com/shirou/gopsutil/v3 v3.24.2/go.mod h1:tSg/594BcA+8UdQU2XcW803GWYgdtauFFPgJCJKZlVk=
github.com/shirou/gopsutil/v3 v3.24.3 h1:eoUGJSmdfLzJ3mxIhmOAhgKEKgQkeOwKpz1NbhVnuPE=
github.com/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
@@ -978,8 +978,8 @@ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg=
golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1075,8 +1075,9 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -1093,7 +1094,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
@@ -1202,8 +1202,6 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+1
View File
@@ -89,6 +89,7 @@ func (dialer *dialer) Dial(params xgress.DialParams) (xt.PeerData, error) {
log.Debug("dialing sdk client hosting service")
dialRequest := edge.NewDialMsg(terminator.Id(), terminator.token, callerId)
dialRequest.PutStringHeader(edge.CircuitIdHeader, params.GetCircuitId().Token)
if pk, ok := circuitId.Data[edge.PublicKeyHeader]; ok {
dialRequest.Headers[edge.PublicKeyHeader] = pk
}
+8 -4
View File
@@ -199,7 +199,7 @@ func (self *edgeClientConn) processConnect(manager state.Manager, req *channel.M
self.listener.bindHandler.HandleXgressBind(x)
conn.ctrlRx = x
// send the state_connected before starting the xgress. That way we can't get a state_closed before we get state_connected
self.sendStateConnectedReply(req, response.PeerData)
self.sendStateConnectedReply(req, response.PeerData, response.CircuitId)
x.Start()
}
@@ -384,7 +384,7 @@ func (self *edgeClientConn) processBindV1(manager state.Manager, req *channel.Me
log.Debug("registered listener for terminator")
log.Debug("returning connection state CONNECTED to client")
self.sendStateConnectedReply(req, nil)
self.sendStateConnectedReply(req, nil, "")
log.Info("created terminator")
}
@@ -504,7 +504,7 @@ func (self *edgeClientConn) processBindV2(manager state.Manager, req *channel.Me
}
}
self.sendStateConnectedReply(req, nil)
self.sendStateConnectedReply(req, nil, "")
if checkResult.replaceExisting {
log.Info("sending replacement terminator success to sdk")
@@ -683,7 +683,7 @@ func (self *edgeClientConn) processTraceRoute(msg *channel.Message, ch channel.C
}
}
func (self *edgeClientConn) sendStateConnectedReply(req *channel.Message, hostData map[uint32][]byte) {
func (self *edgeClientConn) sendStateConnectedReply(req *channel.Message, hostData map[uint32][]byte, circuitId string) {
connId, _ := req.GetUint32Header(edge.ConnIdHeader)
msg := edge.NewStateConnectedMsg(connId)
@@ -691,6 +691,10 @@ func (self *edgeClientConn) sendStateConnectedReply(req *channel.Message, hostDa
msg.PutBoolHeader(edge.RouterProvidedConnId, true)
}
if circuitId != "" {
msg.PutStringHeader(edge.CircuitIdHeader, circuitId)
}
for k, v := range hostData {
msg.Headers[int32(k)] = v
}
+8 -1
View File
@@ -343,7 +343,14 @@ func (self *Service) GetConfigOfType(configType string, target interface{}) (boo
pfxlog.Logger().Debugf("no service config of type %v defined for service %v", configType, self.Name)
return false, nil
}
if err := mapstructure.Decode(configMap, target); err != nil {
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
DecodeHook: mapstructure.StringToTimeDurationHookFunc(),
Result: target,
})
if err != nil {
return false, fmt.Errorf("unable construct decoder (%w)", err)
}
if err := decoder.Decode(configMap); err != nil {
pfxlog.Logger().WithError(err).Debugf("unable to decode service configuration for of type %v defined for service %v", configType, self.Name)
return true, fmt.Errorf("unable to decode service config structure: %w", err)
}
+5 -1
View File
@@ -245,7 +245,11 @@ func (self *echoServer) accept(connType string, listener net.Listener) {
if err != nil {
panic(err)
}
log.Infof("%v: connection received: %v", connType, conn)
circuitId := ""
if edgeConn, ok := conn.(edge.Conn); ok {
circuitId = edgeConn.GetCircuitId()
}
log.WithField("circuitId", circuitId).Infof("%v: connection received: %v", connType, conn)
go self.echo(connType, conn)
}
}
+9 -5
View File
@@ -94,10 +94,14 @@ func (self *zcatAction) run(_ *cobra.Command, args []string) {
var conn net.Conn
var err error
var circuitId string
log.Debugf("dialing %v:%v", network, addr)
if network == "tcp" || network == "udp" {
conn, err = net.Dial(network, addr)
if err != nil {
log.WithError(err).Fatalf("unable to dial %v:%v", network, addr)
}
} else if network == "ziti" {
zitiConfig, cfgErr := ziti.NewConfigFromFile(self.configFile)
if cfgErr != nil {
@@ -121,15 +125,15 @@ func (self *zcatAction) run(_ *cobra.Command, args []string) {
Identity: dialIdentifier,
}
conn, err = zitiContext.DialWithOptions(addr, dialOptions)
if err != nil {
log.WithError(err).Fatalf("unable to dial %v:%v", network, addr)
}
circuitId = conn.(edge.Conn).GetCircuitId()
} else {
log.Fatalf("invalid network '%v'. valid values are ['ziti', 'tcp', 'udp']", network)
}
if err != nil {
log.WithError(err).Fatalf("unable to dial %v:%v", network, addr)
}
log.Debugf("connected to %v:%v", network, addr)
log.WithField("circuitId", circuitId).Debugf("connected to %v:%v", network, addr)
go self.copy(conn, os.Stdin)
self.copy(os.Stdout, conn)
+7 -8
View File
@@ -14,11 +14,11 @@ require (
github.com/michaelquigley/pfxlog v0.6.10
github.com/openziti/agent v1.0.16
github.com/openziti/channel/v2 v2.0.122
github.com/openziti/edge-api v0.26.13
github.com/openziti/edge-api v0.26.14
github.com/openziti/fablab v0.5.42
github.com/openziti/foundation/v2 v2.0.40
github.com/openziti/identity v1.0.73
github.com/openziti/sdk-golang v0.23.14
github.com/openziti/sdk-golang v0.23.15
github.com/openziti/storage v0.2.33
github.com/openziti/transport/v2 v2.0.125
github.com/openziti/ziti v0.28.3
@@ -49,7 +49,7 @@ require (
github.com/blang/semver v3.5.1+incompatible // indirect
github.com/boltdb/bolt v1.3.1 // indirect
github.com/c-bata/go-prompt v0.2.6 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/coreos/go-iptables v0.7.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dgryski/dgoogauth v0.0.0-20190221195224-5a805980a5f3 // indirect
@@ -139,7 +139,7 @@ require (
github.com/openziti/jwks v1.0.3 // indirect
github.com/openziti/metrics v1.2.48 // indirect
github.com/openziti/runzmd v1.0.41 // indirect
github.com/openziti/secretstream v0.1.17 // indirect
github.com/openziti/secretstream v0.1.18 // indirect
github.com/openziti/x509-claims v1.0.3 // indirect
github.com/openziti/xweb/v2 v2.1.0 // indirect
github.com/openziti/ziti-db-explorer v1.1.3 // indirect
@@ -157,7 +157,7 @@ require (
github.com/russross/blackfriday v1.6.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/shirou/gopsutil/v3 v3.24.2 // indirect
github.com/shirou/gopsutil/v3 v3.24.3 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
@@ -189,13 +189,12 @@ require (
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
golang.org/x/image v0.13.0 // indirect
golang.org/x/mod v0.15.0 // indirect
golang.org/x/oauth2 v0.18.0 // indirect
golang.org/x/oauth2 v0.19.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.18.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
gopkg.in/AlecAivazis/survey.v1 v1.8.7 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/resty.v1 v1.12.0 // indirect
+14 -16
View File
@@ -113,8 +113,8 @@ github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBT
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/c-bata/go-prompt v0.2.6 h1:POP+nrHE+DfLYx370bedwNhsqmpCUynWPxuHi0C5vZI=
github.com/c-bata/go-prompt v0.2.6/go.mod h1:/LMAke8wD2FsNu9EXNdHxNLbd9MedkPnCdfpU9wwHfY=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
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 v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -592,8 +592,8 @@ github.com/openziti/channel/v2 v2.0.122 h1:MPALuLUuTsW2QJzaoRkrP/wGqhIeWtSsrnxt2
github.com/openziti/channel/v2 v2.0.122/go.mod h1:n4r/pWTFYJy98hEtf4ATYVHU70OePjoM8JJzrIvXvZg=
github.com/openziti/dilithium v0.3.3 h1:PLgQ6PMNLSTzCFbX/h98cmudgz/cU6TmjdSv5NAPD8k=
github.com/openziti/dilithium v0.3.3/go.mod h1:vsCjI2AU/hon9e+dLhUFbCNGesJDj2ASgkySOcpmvjo=
github.com/openziti/edge-api v0.26.13 h1:lWAHu04nk7a0AEnJBjmwijUIEE+NvNAiOcdg11dxbIY=
github.com/openziti/edge-api v0.26.13/go.mod h1:aTRqB9J/6ISbw9+YWjzD0tvWAXY98m8yWcbiGNqAQTU=
github.com/openziti/edge-api v0.26.14 h1:BpxKavDVdykOY7GSdKXi7klv9Im4vw7bTMujz3wFE1Q=
github.com/openziti/edge-api v0.26.14/go.mod h1:aTRqB9J/6ISbw9+YWjzD0tvWAXY98m8yWcbiGNqAQTU=
github.com/openziti/fablab v0.5.42 h1:vENJKfEba2T4sSLwlKDL/IzBYfY8iHnhc4umf6IESiY=
github.com/openziti/fablab v0.5.42/go.mod h1:HDT06y1QX8kO8ZQrgHvZmJsvc8iRybESGtlDLDII4ks=
github.com/openziti/foundation/v2 v2.0.40 h1:8oXL77egZjnQuKuxPTHiBOh+X/I2mSJefIbnLSv8rFI=
@@ -606,10 +606,10 @@ github.com/openziti/metrics v1.2.48 h1:bDUcWSTWM4vXh4YU8z953Q/vtlUjtH+pSaQviKzB5
github.com/openziti/metrics v1.2.48/go.mod h1:rLFoXigAFb5clCDqe/RlvFFjlaTr9Li7iEn3OxInmb0=
github.com/openziti/runzmd v1.0.41 h1:Iuwe91Lzq63ux2R6+VIWEvcEKhpKkPb1QVNwrJHOuDA=
github.com/openziti/runzmd v1.0.41/go.mod h1:T79oGLLJNnAhHzcfnlrOR39S2XGkzwYZLZh62xee0wk=
github.com/openziti/sdk-golang v0.23.14 h1:usGFwrc7jcGkvas5TVLWQgdWs/FBUZrORb6jV+KM2eY=
github.com/openziti/sdk-golang v0.23.14/go.mod h1:mM7C6QMcEZwVhBLwmrq8PtBMyBbXXoKr186CDpTx5rI=
github.com/openziti/secretstream v0.1.17 h1:bcaPGGpUl0+3GzfQkshKh5slUE7QDXxFq3vyDQgHkCA=
github.com/openziti/secretstream v0.1.17/go.mod h1:gosi8ohW+dAHhz1h/MjZEcEVWO0jisWqWjEjmx7oAEs=
github.com/openziti/sdk-golang v0.23.15 h1:+h+zin2CB6nP8e2Sqi2Jxo4Sbo3wTp8PIfh7QNm4lPA=
github.com/openziti/sdk-golang v0.23.15/go.mod h1:aYvN+PCUV2AHPcbgcG1Khgso5TbmNaLMke0ByshU4Hs=
github.com/openziti/secretstream v0.1.18 h1:bMHI4ez6pVSGFzHCHHn6imkaCYqd3o9Oa8gDObf8icI=
github.com/openziti/secretstream v0.1.18/go.mod h1:gosi8ohW+dAHhz1h/MjZEcEVWO0jisWqWjEjmx7oAEs=
github.com/openziti/storage v0.2.33 h1:15WKxJ0J1GCNOMmOkoosjoxKN2Hrm4p3g8p9WAiMS9Y=
github.com/openziti/storage v0.2.33/go.mod h1:AbE5KkTVlXVFHRqpc7Ug3eFpNOc1HFBFwNIYn8Rtp+s=
github.com/openziti/transport/v2 v2.0.125 h1:6kDfabGFIE2+UPyvJVtfI43CNKcMwNOrCRX602CbDU4=
@@ -700,8 +700,8 @@ 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/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shirou/gopsutil/v3 v3.24.2 h1:kcR0erMbLg5/3LcInpw0X/rrPSqq4CDPyI6A6ZRC18Y=
github.com/shirou/gopsutil/v3 v3.24.2/go.mod h1:tSg/594BcA+8UdQU2XcW803GWYgdtauFFPgJCJKZlVk=
github.com/shirou/gopsutil/v3 v3.24.3 h1:eoUGJSmdfLzJ3mxIhmOAhgKEKgQkeOwKpz1NbhVnuPE=
github.com/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
@@ -1005,8 +1005,8 @@ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg=
golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1102,8 +1102,9 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -1120,7 +1121,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
@@ -1229,8 +1229,6 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=