Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jurisdiction support for GDPR & FedRAMP #34

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

Brayden
Copy link
Owner

@Brayden Brayden commented Nov 6, 2024

Purpose

This code allows users to deploy their durable objects in a manner that adheres to GDPR protocol. Values you can choose for JURISDICTION in your wrangler file include:

  • eu
  • fedramp

If no entry exists for JURISDICTION then it will fallback to using the REGION as a suggested deployment region, and if no region is specified then a normal deployment happens where the first request origin location to the DO is likely where the DO will exist.

Tasks

  • Verify deployment succeeds
  • Verify colo value adheres to eu and fedramp locations in the following cURL

Verify

curl --location 'https://starbasedb.YOUR-IDENTIFIER.workers.dev/status/trace' \
--header 'Authorization: Bearer ABC123' \
--header 'Content-Type: application/json' \
--data ''

Currently it appears we are receiving errors when deploying the durable object and attempting to access it with the above cURL. Here is the stacktrace:

{
  "truncated": false,
  "executionModel": "stateless",
  "outcome": "exception",
  "scriptVersion": {
    "id": "f2ce52cf-ff42-4a92-8f0b-a568577fd195"
  },
  "scriptName": "starbasedb",
  "diagnosticsChannelEvents": [],
  "exceptions": [
    {
      "stack": "    at async Object.fetch (index.js:1247:12)",
      "name": "Error",
      "message": "Internal error while starting up Durable Object storage caused object to be reset.",
      "timestamp": 1730909659548
    }
  ],
  "logs": [],
  "eventTimestamp": 1730909659249,
  "event": {
    "request": {
      "url": "https://starbasedb.YOUR-IDENTIFIER.dev/status/trace",
      "method": "GET",
      "headers": {
        "accept": "*/*",
        "accept-encoding": "gzip, br",
        "authorization": "REDACTED",
        "cache-control": "no-cache",
        "cf-connecting-ip": "24.112.251.244",
        "cf-ipcountry": "US",
        "cf-ray": "8de6603a4ec4dda6",
        "cf-visitor": "{\"scheme\":\"https\"}",
        "connection": "Keep-Alive",
        "content-type": "application/json",
        "host": "starbasedb.YOUR-IDENTIFIER.workers.dev",
        "postman-token": "REDACTED",
        "user-agent": "PostmanRuntime/7.39.1",
        "x-forwarded-proto": "https",
        "x-outerbase-source-token": "REDACTED",
        "x-real-ip": "24.112.251.244",
        "x-starbase-source": "external"
      },
      "cf": {
        "clientTcpRtt": 36,
        "longitude": "-80.13670",
        "httpProtocol": "HTTP/1.1",
        "tlsCipher": "AEAD-AES128-GCM-SHA256",
        "continent": "NA",
        "asn": 27364,
        "clientAcceptEncoding": "gzip, deflate, br",
        "country": "US",
        "verifiedBotCategory": "",
        "tlsClientAuth": {
          "certIssuerDNLegacy": "",
          "certIssuerSKI": "",
          "certSubjectDNRFC2253": "",
          "certSubjectDNLegacy": "",
          "certFingerprintSHA256": "",
          "certNotBefore": "",
          "certSKI": "",
          "certSerial": "",
          "certIssuerDN": "",
          "certVerified": "NONE",
          "certNotAfter": "",
          "certSubjectDN": "",
          "certPresented": "0",
          "certRevoked": "0",
          "certIssuerSerial": "",
          "certIssuerDNRFC2253": "",
          "certFingerprintSHA1": ""
        },
        "tlsExportedAuthenticator": {
          "clientFinished": "924b6c6998b8b57fd1222e23d3f0722a08648d4b56b79f5057962a19282bdd14",
          "clientHandshake": "1209b74b97c80d47aac6eddc5f30d23257d83c9c206548b4189c4e0f20c40769",
          "serverHandshake": "97f7bf3ed27d78a04ca5aed0b288c3bcbc14617b4aece30ddeb9b820ca4811e2",
          "serverFinished": "a5542f301964c95bca55df64a955ddb6d72d322b1f52bd4e55270eeddaa083d5"
        },
        "tlsVersion": "TLSv1.3",
        "colo": "IAD",
        "tlsClientHelloLength": "508",
        "edgeRequestKeepAliveStatus": 1,
        "requestPriority": "",
        "tlsClientExtensionsSha1": "/KdboeBKvsYpmQ6za4zdVuBsiNI=",
        "tlsClientRandom": "49SOmhKB4z6XYh6xv0ohhV7snfpqZ9rLtRpV1lT5M8U="
      }
    },
    "response": {
      "status": 500
    }
  },
  "id": 0
}

Before

After

@Brayden Brayden added the enhancement New feature or request label Nov 6, 2024
@Brayden Brayden self-assigned this Nov 6, 2024
@Brayden Brayden changed the title Jurisdiction support for GDPR Jurisdiction support for GDPR & FedRAMP Nov 6, 2024
@daliborgogic
Copy link

Keep in mind that jurisdiction restrictions are not implemented inworkerd.

@Brayden
Copy link
Owner Author

Brayden commented Nov 7, 2024

Keep in mind that jurisdiction restrictions are not implemented inworkerd.

Well, this explains so much. Thanks @daliborgogic!

@Brayden
Copy link
Owner Author

Brayden commented Nov 7, 2024

Keep in mind that jurisdiction restrictions are not implemented inworkerd.

Well, this explains so much. Thanks @daliborgogic!

Maybe I spoke a little too quickly before consuming coffee. After taking another look at the code, am I not already trying to apply the jurisdiction to the Durable Object?

const namespace = env.DATABASE_DURABLE_OBJECT.jurisdiction(env.JURISDICTION as Jurisdiction);
id = namespace.idFromName(DURABLE_OBJECT_ID);
stub = namespace.get(id);

Unless I'm missing a bigger piece here. Thoughts @daliborgogic?

@daliborgogic
Copy link

daliborgogic commented Nov 7, 2024

Need to check if jurisdiction is in cf

if (env.JURISDICTION && request.cf.jurisdiction) {
  // If jurisdiction is specified, it takes precedence over region
} else {
  // Fall back to region-based routing if no jurisdiction is specified
}

edit: regarding GDPR & FedRAMP imho is better to use Regional Services. Because Workers may still access Durable Objects constrained to a jurisdiction from anywhere in the world.

@Brayden
Copy link
Owner Author

Brayden commented Nov 7, 2024

Need to check if jurisdiction is in cf

if (env.JURISDICTION && request.cf.jurisdiction) {
  // If jurisdiction is specified, it takes precedence over region
} else {
  // Fall back to region-based routing if no jurisdiction is specified
}

edit: regarding GDPR & FedRAMP imho is better to use Regional Services. Because Workers may still access Durable Objects constrained to a jurisdiction from anywhere in the world.

Thanks for pointing that out @daliborgogic :)

I don't disagree that Regional Services is the better approach for GDPR and FedRAMP compliance – however, there's no good way to enforce those rules via Wrangler. It would be wonderful if I could declare it in my wrangler.toml file like something below and the infra would just know this worker type needs to be routed to an EU center. Not sure how this is handled on the Cloudflare side of things either so could just simply not be possible now or in the future.

[[data_localization]]
region = "eu"

Going back to your previous suggestion... When I do as suggested, I still don't see the colo value of a request made within the Durable Object to be in the EU region with the code I have below. To be fair though when I look at the logs in CF of a request made I don't see an entry for cf.jurisdiction.

let id: DurableObjectId;
let stub: DurableObjectStub;

if (env.JURISDICTION && request.cf?.jurisdiction) {
    // If jurisdiction is specified, it takes precedence over region
    const namespace = env.DATABASE_DURABLE_OBJECT.jurisdiction(env.JURISDICTION as Jurisdiction);
    id = namespace.idFromName(DURABLE_OBJECT_ID);
    stub = namespace.get(id);
} else {
    // Fall back to region-based routing if no jurisdiction is specified
    id = env.DATABASE_DURABLE_OBJECT.idFromName(DURABLE_OBJECT_ID);
    const region = env.REGION ?? RegionLocationHint.AUTO;
    stub = region !== RegionLocationHint.AUTO 
        ? env.DATABASE_DURABLE_OBJECT.get(id, { locationHint: region as DurableObjectLocationHint })
        : env.DATABASE_DURABLE_OBJECT.get(id);
}

@daliborgogic
Copy link

"Durable Objects do not currently change locations after they are created."

cf.jurisdiction

My mistake, sorry. I'll try to do a minimal reproduction

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants