|
16 | 16 | "* [Jupyter Notebook](https://jupyter.org/install)\n",
|
17 | 17 | "* [Docker](https://docs.docker.com/get-started/get-docker/)\n",
|
18 | 18 | "* [Docker compose](https://docs.docker.com/compose/install/)\n",
|
| 19 | + "* [curl](https://curl.se)\n", |
19 | 20 | "* [CipherStash account](https://cipherstash.com/signup)\n",
|
20 | 21 | "* [CipherStash CLI](https://github.com/cipherstash/cli-releases/releases/latest)"
|
21 | 22 | ]
|
|
276 | 277 | "! docker compose up postgres -d"
|
277 | 278 | ]
|
278 | 279 | },
|
| 280 | + { |
| 281 | + "cell_type": "markdown", |
| 282 | + "id": "7f68e37d-210d-468d-b267-1b6930ba7957", |
| 283 | + "metadata": {}, |
| 284 | + "source": [ |
| 285 | + "The command above should start PostgreSQL.\n", |
| 286 | + "At any point, you can check the logs to see if there are any errors in your terminal window.\n", |
| 287 | + "From the directory where your docker-copmose.yml is located (`jupyter_notebook/` by default):\n", |
| 288 | + "\n", |
| 289 | + "> docker compose logs -f postgres" |
| 290 | + ] |
| 291 | + }, |
279 | 292 | {
|
280 | 293 | "cell_type": "markdown",
|
281 | 294 | "id": "d9df0769-503c-4921-bb83-f4ff2a5f8a6d",
|
|
293 | 306 | "id": "85888d9c-388b-4026-aaac-d72cedbec99f",
|
294 | 307 | "metadata": {},
|
295 | 308 | "source": [
|
296 |
| - "### Install database extensions" |
| 309 | + "### Install database extensions and EQL" |
297 | 310 | ]
|
298 | 311 | },
|
299 | 312 | {
|
|
303 | 316 | "metadata": {},
|
304 | 317 | "outputs": [],
|
305 | 318 | "source": [
|
306 |
| - "! PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres cipherstash_getting_started < install.sql # should output messages like `CREATE *`" |
307 |
| - ] |
308 |
| - }, |
309 |
| - { |
310 |
| - "cell_type": "markdown", |
311 |
| - "id": "d91bc1e4-9a22-4561-bc37-052adaaf4cef", |
312 |
| - "metadata": {}, |
313 |
| - "source": [ |
314 |
| - "### Install EQL" |
315 |
| - ] |
316 |
| - }, |
317 |
| - { |
318 |
| - "cell_type": "code", |
319 |
| - "execution_count": null, |
320 |
| - "id": "dbfe2a97-f392-48e9-be64-e906684015b3", |
321 |
| - "metadata": {}, |
322 |
| - "outputs": [], |
323 |
| - "source": [ |
324 |
| - "! PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres cipherstash_getting_started < cipherstash_encrypt_eql.sql # should output messages like `CREATE *`" |
| 319 | + "! curl https://raw.githubusercontent.com/cipherstash/encrypt-query-language/refs/heads/main/release/cipherstash-encrypt-dsl.sql | PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres cipherstash_getting_started" |
325 | 320 | ]
|
326 | 321 | },
|
327 | 322 | {
|
|
380 | 375 | "! docker compose up proxy -d"
|
381 | 376 | ]
|
382 | 377 | },
|
| 378 | + { |
| 379 | + "cell_type": "markdown", |
| 380 | + "id": "97fde254-3eb5-4036-bf82-b49ec2a77f30", |
| 381 | + "metadata": {}, |
| 382 | + "source": [ |
| 383 | + "The command above should start CipherStash Proxy.\n", |
| 384 | + "At any point, you can check the logs to see if there are any errors in your terminal window.\n", |
| 385 | + "From the directory where your docker-copmose.yml is located (`jupyter_notebook/` by default):\n", |
| 386 | + "\n", |
| 387 | + "> docker compose logs -f proxy" |
| 388 | + ] |
| 389 | + }, |
383 | 390 | {
|
384 | 391 | "cell_type": "markdown",
|
385 | 392 | "id": "0400e206-a337-404c-acc9-9706e626e94e",
|
|
401 | 408 | "\n",
|
402 | 409 | "There are classes prefixed with `Cs` defined in `cs_types.py` which handles conversion between the format CypherStash Proxy requires and the format for Python.\n",
|
403 | 410 | "\n",
|
404 |
| - "In order to encrypt and store plaintext values, CipherStash Proxy requires encrypted columns to be in JSONB format like:\n", |
405 |
| - "```\n", |
406 |
| - "{\n", |
407 |
| - " \"k\": \"pt\",\n", |
408 |
| - " \"p\": \"hell, world\",\n", |
409 |
| - " \"i\": {\n", |
410 |
| - " \"t\": \"examples\",\n", |
411 |
| - " \"c\": \"encrypted_utf8_str\"\n", |
412 |
| - " },\n", |
413 |
| - " \"v\": 1,\n", |
414 |
| - "}\n", |
415 |
| - "```\n", |
416 |
| - "\n", |
417 |
| - "In Python, this conversion can be done by creating an object of `CsText` as:\n", |
| 411 | + "In order to encrypt and store plaintext values, CipherStash Proxy requires encrypted columns in its specific format.\n", |
| 412 | + "In Python, this conversion is done by creating an object of `CsText` as:\n", |
418 | 413 | "```\n",
|
419 | 414 | "txt = CsText(\"hell, world\", \"examples\", \"encrypted_utf8_str\")\n",
|
420 | 415 | "txt.to_db_format()\n",
|
|
440 | 435 | "metadata": {},
|
441 | 436 | "outputs": [],
|
442 | 437 | "source": [
|
443 |
| - "! pip install psycopg2 sqlalchemy" |
| 438 | + "%pip install psycopg2 sqlalchemy" |
444 | 439 | ]
|
445 | 440 | },
|
446 | 441 | {
|
|
462 | 457 | "outputs": [],
|
463 | 458 | "source": [
|
464 | 459 | "from cs_types import *\n",
|
465 |
| - "from psycopg2.extras import RealDictCursor" |
| 460 | + "from psycopg2.extras import RealDictCursor\n", |
| 461 | + "\n", |
| 462 | + "print(\"Importing done.\")" |
466 | 463 | ]
|
467 | 464 | },
|
468 | 465 | {
|
469 | 466 | "cell_type": "markdown",
|
470 | 467 | "id": "6ac472ff-81d1-418a-998b-975b2b3f3a05",
|
471 | 468 | "metadata": {},
|
472 | 469 | "source": [
|
473 |
| - "## Insert end query encrypted data\n", |
| 470 | + "## Insert test record\n", |
474 | 471 | "\n",
|
475 | 472 | "With the database extensions, EQL, and application specific data types installed together with the type definitions for Python, your setup is now ready to encrypt and decrypt data."
|
476 | 473 | ]
|
477 | 474 | },
|
478 |
| - { |
479 |
| - "cell_type": "markdown", |
480 |
| - "id": "0bd5e34e-4840-4398-be46-3cc6b5969e5f", |
481 |
| - "metadata": {}, |
482 |
| - "source": [ |
483 |
| - "To check what the JSONB format looks like, run the following:" |
484 |
| - ] |
485 |
| - }, |
486 |
| - { |
487 |
| - "cell_type": "code", |
488 |
| - "execution_count": null, |
489 |
| - "id": "d2111106-e117-46c2-b1a1-ae8b4bb8598e", |
490 |
| - "metadata": {}, |
491 |
| - "outputs": [], |
492 |
| - "source": [ |
493 |
| - "CsText(\"hello, python\", \"examples\", \"encrypted_utf8_str\").to_db_format()" |
494 |
| - ] |
495 |
| - }, |
496 | 475 | {
|
497 | 476 | "cell_type": "markdown",
|
498 | 477 | "id": "3c571924-c592-447b-88a7-fef6b50f2114",
|
|
539 | 518 | "id": "524c68bc-be47-4887-881b-1af0b365e259",
|
540 | 519 | "metadata": {},
|
541 | 520 | "source": [
|
542 |
| - "Check What it looks like from both regular PostgreSQL running on port 5432 and CipherStash Proxy running on port 6432:" |
| 521 | + "This should insert a single row in the encrypted `examples` table as:\n", |
| 522 | + "\n", |
| 523 | + "|encrypted_int|encrypted_boolean|encrypted_date|encrypted_float|encrypted_utf8_str|\n", |
| 524 | + "|---|-----|--------------|----|------------|\n", |
| 525 | + "|-51|false|<current_date>|-0.5|hello, world|\n", |
| 526 | + "\n", |
| 527 | + "You can check what it looks like from both regular PostgreSQL running on port 5432 and CipherStash Proxy running on port 6432.\n", |
| 528 | + "To look at the data through CipherStash Proxy, run the following:" |
543 | 529 | ]
|
544 | 530 | },
|
545 | 531 | {
|
|
553 | 539 | "!printf '\\\\x \\n select * from examples limit 1;' | PGPASSWORD=postgres psql -h localhost -p 6432 -U postgres cipherstash_getting_started"
|
554 | 540 | ]
|
555 | 541 | },
|
| 542 | + { |
| 543 | + "cell_type": "markdown", |
| 544 | + "id": "802cbfb3-9869-43ce-adae-1367b23ea52e", |
| 545 | + "metadata": {}, |
| 546 | + "source": [ |
| 547 | + "To look at the data directly on the PostgreSQL server, run the following:" |
| 548 | + ] |
| 549 | + }, |
556 | 550 | {
|
557 | 551 | "cell_type": "code",
|
558 | 552 | "execution_count": null,
|
|
569 | 563 | "id": "564d2bc7-0c45-4e5f-ba0a-5919961ee9ce",
|
570 | 564 | "metadata": {},
|
571 | 565 | "source": [
|
572 |
| - "In the above example, not all fields are populated, but the populated fields should contain JSONB values including the encrypted values, with \"k\" set to \"ct\" indicating \"cipher text\"." |
| 566 | + "In the above example, not all fields are populated, but the populated fields contain JSONB values including the encrypted values." |
573 | 567 | ]
|
574 | 568 | },
|
575 | 569 | {
|
|
668 | 662 | "print(\"created data for MATCH and ORE queries\")"
|
669 | 663 | ]
|
670 | 664 | },
|
| 665 | + { |
| 666 | + "cell_type": "markdown", |
| 667 | + "id": "4e67be50-948d-4832-80e9-6411538cf974", |
| 668 | + "metadata": {}, |
| 669 | + "source": [ |
| 670 | + "The example code above should insert rows like these in the examples table:\n", |
| 671 | + "\n", |
| 672 | + "| | encrypted_utf_data | encrypted_float| encrypted_jsonb | |\n", |
| 673 | + "|--|---|---|---|---|\n", |
| 674 | + "| |hello, python| | | |\n", |
| 675 | + "| |hello, jupyter| | | |\n", |
| 676 | + "| | | 100.1 | | |\n", |
| 677 | + "| | | 100.2 | | |\n", |
| 678 | + "| | | | {\"top\": {\"level1\": {\"level2\": [\"a\", \"b\", \"c\"]}}} | |\n", |
| 679 | + "| | | | {\"top\": {\"level1\": {\"another_key\": [\"a\"]}}} | |\n" |
| 680 | + ] |
| 681 | + }, |
671 | 682 | {
|
672 | 683 | "cell_type": "markdown",
|
673 | 684 | "id": "c2a6b812-980c-4958-a55e-45551cb474c2",
|
674 | 685 | "metadata": {},
|
675 | 686 | "source": [
|
676 | 687 | "### Partial matching\n",
|
677 | 688 | "\n",
|
678 |
| - "Now, a query can be run to look for a record in the `examples` table where `encrypted_utf_8_str` field contains text `\"pyth\"`:" |
| 689 | + "Now, a query can be run to look for a record in the `examples` table where `encrypted_utf_8_str` field contains text `\"pyth\"`, which should match `\"hello, python\"`:" |
679 | 690 | ]
|
680 | 691 | },
|
681 | 692 | {
|
|
726 | 737 | "source": [
|
727 | 738 | "### ORE queries\n",
|
728 | 739 | "\n",
|
729 |
| - "Finally, a query for a record with `encrypted_float` that is larger than `100.15`:" |
| 740 | + "Finally, a query for a record with `encrypted_float` that is larger than `100.15` which should match `100.2`:" |
730 | 741 | ]
|
731 | 742 | },
|
732 | 743 | {
|
|
751 | 762 | "### JSONB\n",
|
752 | 763 | "\n",
|
753 | 764 | "A record can be found using the JSONB path.\n",
|
754 |
| - "This only works with a path from the root with no missing nodes in the middle." |
| 765 | + "This only works with a path from the root with no missing nodes in the middle.\n", |
| 766 | + "The following matches the JSONB field containing keys `top`, `level1` and `level2`:" |
755 | 767 | ]
|
756 | 768 | },
|
757 | 769 | {
|
|
0 commit comments