|
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