>백엔드 개발 >Golang >Embedded Instruqt Lab에 대한 액세스 간소화

Embedded Instruqt Lab에 대한 액세스 간소화

Patricia Arquette
Patricia Arquette원래의
2024-10-03 20:07:301075검색

잠재 고객과 고객에게 매우 기술적인 주제를 어떻게 가르치나요? 어떻게 하면 원활한 승차감을 얻을 수 있나요?

Isovalent에서는 사용자에게 최대한 원활한 학습 경험을 제공하기 위해 최선을 다하고 있습니다. Isovalent는 Kubernetes를 위한 사실상 클라우드 네트워킹 플랫폼인 Cilium의 창시자입니다. 우리는 네트워킹과 보안을 좋아하지만 사람들이 이를 어려운 주제로 생각할 수도 있다는 점에 감사드립니다. Kubernetes 네트워킹 학습을 재미있게 만들 수 있다고 생각하여 학습 경험을 게임화하는 것이 중요합니다.
Instruqt는 기술적으로 발전하고 사용자의 관심을 끌 수 있는 실습 랩을 구축할 수 있는 훌륭한 플랫폼을 제공합니다.

또한 우리는 사용자 경험이 원활해야 하고 프로세스가 완전히 자동화되어야 한다고 믿습니다.
다행히 Instruqt graphQL API를 활용하면 많은 작업을 수행할 수 있습니다.
이를 위해 우리는 자체 instruqt-go 라이브러리를 작성했으며 이를 오픈 소스로 결정했습니다. 이 라이브러리는 개발자가 Instruqt 플랫폼을 쉽게 자동화하고 통합할 수 있도록 설계되었습니다.

Instruqt 연구소를 게시할 때의 문제 중 하나는 Instruqt의 사용자 정보를 자체 데이터베이스 또는 CRM의 정보와 연결하는 것입니다.
이 첫 번째 게시물에서는 instruqt-go를 사용하여 다음과 같은 프록시를 구축하는 방법을 안내합니다.

  • 사용자 식별자(예: HubSpot 토큰)를 수집합니다.
  • 사용자 신원을 확인합니다.
  • Instruqt API를 통해 생성된 고유한 액세스 토큰을 사용하여 사용자를 연구실로 리디렉션합니다.

그런 다음 Google Cloud Functions에 함수를 게시합니다.

프록시가 필요한 이유

연구소에서 사용자 정보를 수집하는 데는 다양한 이유가 있습니다.

  • 실습 완료 시 배지를 생성할 수 있으면 유용합니다(향후 게시물에서 자세히 설명하겠습니다).
  • 사용자에게 실험실 진행 상황을 보여 주어 어떤 실험실을 선택해야 할지 알 수 있습니다(예: Cilium Labs 지도 참조).

Streamlining Access to Embedded Instruqt Labs

사용자 데이터를 전달하는 방법

사용자 데이터를 Instruqt 트랙에 전달하는 방법에는 여러 가지가 있습니다.

맞춤 매개변수

Instruqt 사용자 정의 매개변수는 트랙을 시작할 때 모든 종류의 정보를 전달하는 데 매우 유용합니다. 이러한 필드는 단순히 icp_ 접두사가 붙은 쿼리 매개변수로 URL에 추가됩니다. 이러한 매개변수는 Instruqt Webhook뿐만 아니라 Instruqt GraphQL API를 통해서도 검색할 수 있으므로 실용적으로 사용할 수 있습니다.

최근까지 Instruqt는 트랙 개발자에게 맞춤 매개변수를 사용하여 사용자 정보(예: 이름, 이메일 또는 토큰)를 전달하도록 권장했습니다.

그러나 맞춤 매개변수 사용에는 몇 가지 단점이 있습니다.

  1. 표준화되어 있지 않으며 Instruqt에서는 이를 해석하지 않습니다. 이는 사용자 세션이 Instruqt 보고서에 익명으로 표시됨을 의미합니다(고유 사용자 수가 잘못될 수 있음).
  2. 기본적으로 암호화되지 않습니다. 물론 자신의 키에 대해 암호화할 수도 있지만 Instruqt는 플레이 보고서에 암호화된 값을 표시합니다.
  3. 사용자가 실습을 다시 시작할 때 맞춤 매개변수가 손실되는 경우를 여러 번 보았습니다. 저는 실제로 이 문제에 대응하기 위해 자체 캐시 데이터베이스를 시작했습니다.

초대

Instruqt 초대를 사용하면 트랙 목록을 만들고 쉽게 액세스할 수 있도록 사용자와 공유할 수 있는 초대 링크를 생성할 수 있습니다. 양식을 통해 사용자 데이터를 수집하도록 초대를 설정할 수 있습니다.

이 사용자 데이터는 Instruqt의 사용자 세부 정보에 추가됩니다(사용자 세부 정보는 사용자 계정에 첨부되지만 Instruqt 팀마다 고유합니다).

이는 워크숍에 매우 실용적이지만 몇 가지 제한 사항이 있습니다.

  1. 초대를 사용하여 모든 실습에 액세스한다는 것은 초대에 게시된 모든 실습이 포함되어야 함을 의미합니다.
  2. 초대에는 자체 랜딩 페이지가 있으므로 Cilium Labs 지도나 기타 키오스크 접근 방식에서는 작동하지 않습니다.

참고: Instruqt는 최근 랜딩 페이지를 조정할 수 있는 초대 형식인 랜딩 페이지를 도입했지만 동일한 장점과 한계를 가지고 있습니다.

제3자 양식

최근 Instruqt는 사용자 정보를 전달하는 또 다른 방법을 추가했는데, 이는 이전 방법의 장점을 모두 결합한 것입니다.

암호화된 PII 방법을 사용하면 pii_tpg 쿼리 매개변수를 삽입 URL에 전달할 수 있습니다. 이는 다음을 의미합니다.

  1. 데이터는 Instruqt에서 제공하는 공개 키를 사용하여 암호화되므로 URL에는 읽을 수 있는 사용자 정보가 포함되지 않습니다.
  2. Instruqt는 pii_tpg 데이터를 이해하고 이를 해독할 수 있는 개인 키를 가지고 있습니다. 이 정보는 마치 초대에 동의한 것처럼 사용자의 세부 정보를 입력하는 데 사용됩니다.
  3. 초대장과 연결되지 않아 어떤 트랙에도 사용 가능합니다.

이 예에서는 이 새로운 방법을 사용할 것입니다. 이는 안전하고 신뢰할 수 있는 방식으로 Instruqt에 정보를 전달하는 것이 오늘날 가장 다재다능하기 때문입니다.

Ein Hinweis zu eingebetteten Token

Wenn Sie eine Track-Seite auf Instruqt besuchen, besteht die Möglichkeit, den Track einzubetten.
Dadurch erhalten Sie eine URL, die ein für den Track eindeutiges Token enthält.

Die Verwendung dieser URL ist zwar völlig zulässig, bedeutet aber auch, dass jeder, der Zugriff auf dieses Token hat, den Track starten kann, wann immer er möchte.

Instruqt hat kürzlich einen API-Aufruf hinzugefügt, um einmalige Token für Tracks zu generieren, sodass URLs, die solche Token verwenden, nur einmal verwendet werden können.

Der Proxy, den wir codieren, wird einmalige Token verwenden, da wir Zugriff auf die API haben und diese problemlos generieren können.

Erstellen des Proxys

Erste Schritte

Erstellen Sie zunächst ein Verzeichnis für Ihre Funktion:

mkdir instruqt-proxy

Gehen Sie in dieses Verzeichnis und initialisieren Sie die Go-Umgebung:

# Replace example.com with the prefix of your choice
go mod init example.com/labs

Nutzung von Google Cloud-Funktionen

Für lokale Tests erstellen Sie ein cmd-Verzeichnis:

mkdir cmd

Erstellen Sie in diesem Verzeichnis eine main.go-Datei mit folgendem Inhalt:

package main

import (
    "log"
    "os"

    // Blank-import the function package so the init() runs
  // Adapt if you replaced example.com earlier
    _ "example.com/labs"

    "github.com/GoogleCloudPlatform/functions-framework-go/funcframework"
)

func main() {
    // Use PORT environment variable, or default to 8080.
    port := "8080"
    if envPort := os.Getenv("PORT"); envPort != "" {
        port = envPort
    }
    if err := funcframework.Start(port); err != nil {
        log.Fatalf("funcframework.Start: %v\n", err)
    }
}

Erstellen der Funktion

Zurück zum instruqt-proxy-Verzeichnis, erstellen Sie eine Proxy.go-Datei und fügen Sie ihr zunächst die Funktion init() zusammen mit den Go-Paketen hinzu, die wir verwenden werden:

package labs

import (
    "fmt"
    "net/http"
    "net/url"
    "os"

    "github.com/GoogleCloudPlatform/functions-framework-go/functions"

    "github.com/isovalent/instruqt-go/instruqt"
)

func init() {
    functions.HTTP("InstruqtProxy", instruqtProxy)
}

Dadurch können Google Cloud Functions die instruqtProxy-Funktion aufrufen, wenn sie initialisiert wird.

Lassen Sie uns diese Funktion schreiben:

const (
    // Replace team name with yours
    instruqtTeam = "isovalent"
)

func instruqtProxy(w http.ResponseWriter, r *http.Request) {
    instruqtToken := os.Getenv("INSTRUQT_TOKEN")

    if instruqtToken == "" {
        w.WriteHeader(http.StatusInternalServerError)
        return
    }

    instruqtClient := instruqt.NewClient(instruqtToken, instruqtTeam)

    // Get user from passed token
    utk := r.URL.Query().Get("utk")
    if utk == "" {
        w.WriteHeader(http.StatusUnauthorized)
        return
    }

    user, err := getUser(utk)
    if err != nil {
        w.WriteHeader(http.StatusUnauthorized)
        return
    }

    labSlug := r.URL.Query().Get("slug")

    url, err := getLabURL(instruqtClient, user, labSlug)
    if err != nil {
        w.WriteHeader(http.StatusNotFound)
        return
    }

    http.Redirect(w, r, url, http.StatusFound)
}

In dieser Funktion:

  1. Rufen Sie das Instruqt-Token aus der Umgebungsvariablen INSTRUQT_TOKEN ab
  2. Initialisieren Sie den Instruqt-API-Client für das Token und das Team
  3. rufen Sie einen utk-Parameter aus den URL-Parametern ab, um den Benutzer zu authentifizieren
  4. Erhalten Sie Benutzerinformationen basierend auf diesem UTK
  5. Rufen Sie den Labor-Slug aus den URL-Parametern ab
  6. Rufen Sie die Labor-URL für die Weiterleitung ab
  7. Leiten Sie den Benutzer mithilfe einer http.Redirect-Funktion um

getLabURL() implementieren

Die getLabURL-Funktion generiert die Weiterleitungs-URL für das Labor basierend auf Benutzerinformationen, dem angeforderten Labor-Slug und dynamischen Informationen aus der Instruqt-API.

Lass es uns schreiben:

const (
    // Replace with your sign-up page format
    labSignupPage = "https://isovalent.com/labs/%s"

    // Adapt to your values
    finishBtnText = "Try your next Lab!"
    finishBtnURL  = "https://labs-map.isovalent.com/map?lab=%s&showInfo=true"
)

func getLabURL(instruqtClient *instruqt.Client, u user, slug string) (string, error) {
    track, err := instruqtClient.GetTrackBySlug(slug)
    if err != nil {
        return "", err
    }

    // Unknown user
    if u.Email == "" {
        url := fmt.Sprintf(labSignupPage, slug)
        return url, nil
    }

    // Get one-time token
    token, err := instruqtClient.GenerateOneTimePlayToken(track.Id)
    if err != nil {
        return "", err
    }

    labURL, err := url.Parse(fmt.Sprintf("https://play.instruqt.com/embed/%s/tracks/%s", instruqtTeam, track.Slug))
    if err != nil {
        return "", err
    }

    // Prepare the fields to encrypt
    encryptedPII, err := instruqtClient.EncryptUserPII(u.FirstName, u.LastName, u.Email)
    if err != nil {
        return "", err
    }

    // Add params
    params := map[string]string{
        "token":             token,
        "pii_tpg":           encryptedPII,
        "show_challenges":   "true",
        "finish_btn_target": "_blank",
        "finish_btn_text":   finishBtnText,
        "finish_btn_url":    fmt.Sprintf(finishBtnURL, track.Slug),
    }

    q := labURL.Query()
    for key, value := range params {
        q.Set(key, value)
    }

    // Encode the parameters
    labURL.RawQuery = q.Encode()

    return labURL.String(), nil
}

Beachten Sie zunächst, dass wir einige neue Konstanten definiert haben, die Sie anpassen können:

  • labSignupPage ist die URL auf Ihrer Website, zu der nicht authentifizierte Benutzer weitergeleitet werden. Es enthält eine Variable für den Labor-Slug.
  • finishBtnText ist der Text, der auf der Schaltfläche „Fertig stellen“ des Labors angezeigt wird.
  • „finishBtnURL“ ist die Aktion der Schaltfläche am Ende des Labs. Es enthält auch eine Variable für den Labor-Slug.

Jetzt erklären wir die Schritte der getLabURL()-Funktion:

  1. Titelinformationen von der Instruqt-API abrufen, Fehlermeldung, wenn sie nicht gefunden werden können.
  2. Wenn der Benutzer unbekannt ist, leiten Sie zur Anmeldeseite weiter.
  3. Generieren Sie ein einmaliges Token für den Zugriff auf eingebettete Gleise.
  4. Generieren Sie die Weiterleitungs-URL.
  5. Benutzerinformationen mit dem PII-Schlüssel der Instruqt-API verschlüsseln.
  6. Fügen Sie alle Parameter (einmaliges Token, verschlüsselte Benutzerinformationen, Optionen für die Schaltfläche „Fertig stellen“) zur Weiterleitungs-URL hinzu.
  7. Kodieren Sie die URL.
  8. Gibt die resultierende URL zurück.

Die getUser()-Funktion

Das letzte Element, das in diesem Proxy fehlt, ist die Funktion getUser(). Ich kann Ihnen hier nicht viel weiterhelfen, da Sie in diesem Teil Ihre eigene Logik einsetzen. Möglicherweise verwenden Sie ein CRM wie Hubspot, um Kontaktinformationen aus der UTK oder einer anderen Datenbank abzurufen, es liegt an Ihnen!

Der Code, den ich Ihnen hier zeige, gibt einfach einen Beispielbenutzer zurück:

/*
 * This is where you add the logic to get user information from your CRM/database.
 */
type user struct {
    FirstName string
    LastName  string
    Email     string
}

func getUser(utk string) (u user, err error) {
    // Implement the logic to get your user information from UTK

    u = user{
        FirstName: "John",
        LastName:  "Doe",
        Email:     "john@doe.com",
    }

    return u, err
}

Testen des Codes

Jetzt, da wir unsere gesamte Proxy.go-Funktion haben, testen wir sie!

Aktualisieren Sie zunächst Ihre go.mod- und go.sum-Dateien mit:

go get ./...
go mod tidy

Gehen Sie in Ihrem Instruqt-Dashboard zu „API-Schlüssel“ und rufen Sie den Wert Ihres API-Schlüssels ab. Exportieren Sie es als Variable in Ihre Shell:

export INSTRUQT_TOKEN=<your_instruqt_token>

Als nächstes starten Sie die Funktion auf Ihrem lokalen Computer:

FUNCTION_TARGET=InstruqtProxy go run ./cmd/main.go

Stellen Sie abschließend in einem anderen Terminal Testanfragen an localhost:8080, wo Ihre Funktion ausgeführt wird (Sie können oben eine PORT-Umgebungsvariable übergeben, um den Port bei Bedarf zu ändern):

curl  -i "localhost:8080/?slug=cilium-getting-started&utk=someUtkValue"

Passen Sie es an, um einen Track Slug zu verwenden, der in Ihrer Instruqt-Organisation vorhanden ist. Wenn der Track existiert, sollten Sie eine 302-Antwort mit der Weiterleitungs-URL erhalten, die ein einmaliges Token für den Zugriff sowie die mit dem PII-Schlüssel verschlüsselten John Doe-Informationen und ein einmaliges Token (beginnend mit ott_) enthält!

Alternatives Testen: mit Docker

Wenn Sie Docker verwenden möchten, um Ihre Funktion lokal zu testen, können Sie eine Docker-Datei in Ihrem aktuellen Verzeichnis erstellen:

FROM golang:1.23

WORKDIR /app

COPY . .

RUN go build -o myapp ./cmd/main.go

ENV DEV=true
ENV PORT=8080

EXPOSE $PORT

CMD ["./myapp"]

Fügen Sie eine docker-compose.yaml-Datei hinzu:

version: '3'
services:
  proxy:
    build: ./
    ports:
      - "8080:8080"
    environment:
      INSTRUQT_TOKEN: ${INSTRUQT_TOKEN}
      FUNCTION_TARGET: InstruqtProxy

Zum Schluss erstellen und starten Sie Ihren Container:

docker-compose up --build

Und Sie können wie zuvor Anfragen an localhost:8080 senden!

Hosting the Proxy on Google Cloud Functions

In order to deploy to Google Cloud, first make sure you are logged in to your Google Cloud project:

gcloud auth application-default login

Create a Secret for the API Token

Next, let's create a new secret for the Instruqt token:

echo -n "$INSTRUQT_TOKEN" | gcloud secrets create instruqt-token --data-file=-

In order to adjust the permissions on this secret, you will need to get your project ID:

PROJECT_NUMBER=$(gcloud projects describe $(gcloud config get-value project) --format="value(projectNumber)")

Then, add the "Secret Manager Secret Accessor" role for the default Compute Engine service account for the project:

gcloud secrets add-iam-policy-binding instruqt-token \
    --member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
    --role="roles/secretmanager.secretAccessor"

Your secret is now ready to be used by the function!

Deploy the Function

You can then deploy the function (adapt the region if needed):

gcloud functions deploy "instruqt-proxy" \
  --gen2 --runtime=go122 --region=europe-west1 --source=. \
  --entry-point="InstruqtProxy" --trigger-http --allow-unauthenticated \
  --set-secrets="INSTRUQT_TOKEN=instruqt-token:latest"

This will upload and build your project, and return the URL to access the function.

This URL will look something like https://europe-west1-.cloudfunctions.net/instruqt-proxy.
You can then test the function using that URL instead of localhost:8080!

Further Considerations

This is a simplified approach to the lab proxy we use at Isovalent. There are things you might want to consider with this implementation:

  • If you have actual user (instead of marketing contact), switch to a proper authentication system (e.g. JWT) instead of UTK.
  • The current implementation will give access to any lab in your collection if you know its slug. You might want to filter them out (using for example track tags).
  • This implementation manages errors but is very basic in logging. We would recommend using Google Cloud logging to easily audit function runs.
  • You might want to pass extra information as custom parameters. For example, we like to pass some form of even or campaign ID. These can then be retrieved via the API as part or the Track structure.
  • If you're using a custom form and redirecting to the proxy, you might want to be sure your CRM/database has already gotten the user information. You can for example implement a retry logic in the proxy function.
  • Invite embed URLs contain the invite ID. If you want to support invites, the proxy could take an optional invite parameter and add it to the URL.

Using the Proxy

This proxy can typically be used to give access to authenticated users in a safe way, while preserving user information in Instruqt reports and making sure embed URLs are not reusable.

Here is an example of usage of this proxy:

  1. Set up lab sign-up pages with the form system of your choice (e.g. using Hubspot forms).
  2. Retrieve a user identifier from the page context (e.g. a Hubspot cookie token).
  3. Redirect users to the proxy, passing the user identifier and lab slug as parameters.

This can allow you to build a series of public sign-up pages for your labs, similar to what we have built on the Isovalent website. It can also be used to build a Kiosk interface, or even a more creative landing page such as the Cilium Labs map, where clicks on the map redirect to the lab proxy.

By making a complex networking technology like Cilium fun with our labs, we have made it the experience for users less intimidating and more approachable. Using our proxy can help you provide a similar user experience to your prospects. Please get in touch if you have any questions.

위 내용은 Embedded Instruqt Lab에 대한 액세스 간소화의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.