nats-io/nsc

Imports with the same name seem to get confused

Closed this issue · 3 comments

Situation

My app has “customers”, each of whom has their own account to keep them nice and separate. There is however a shared database service that customers can make use of. This works as follows:

To add something to the database: The customer sends the item to the subject streams.database (This is a private stream, exported by the customer, imported by the database)

The database runs as a separate account, mapping the subjects as follows:

The streams.database stream is imported as ingest.{customerName}

The {customerName} is used in the subjects so that the database knows which customer a query has come from.

Problem

When adding a second import to the database account using interactive mode NSC claims:

Error: account already imports stream "streams.database" from ABJX476VE7NKC5IBBNEWAVAWNNXW3W7P3WBP22QYZ2EHAQK73O27CJGK

Which is not true.

Replication

Creating accounts:

vscode ➜ /tmp $ nsc init
? enter a configuration directory ./
? Select an operator Create Operator
? name your operator, account and user example
[ OK ] created operator example
[ OK ] created system_account: name:SYS id:ADAUPTVMMVDOTX34LGHN6S4GQMDUYVAPOJ477MPWEODOOFVKFT5OZXFC
[ OK ] created system account user: name:sys id:UC6CFISTAB56PW7YQ22IDRUC7HFX4QVTJ3FOH763OB4W6RKRXDANTART
[ OK ] system account user creds file stored in `~/.local/share/nats/nsc/keys/creds/example/SYS/sys.creds`
[ OK ] created account example
[ OK ] created user "example"
[ OK ] project jwt files created in `/tmp`
[ OK ] user creds file stored in `~/.local/share/nats/nsc/keys/creds/example/example/example.creds`
> to run a local server using this configuration, enter:
>   nsc generate config --mem-resolver --config-file <path/server.conf>
> then start a nats-server using the generated config:
>   nats-server -c <path/server.conf>
all jobs succeeded

vscode ➜ /tmp $ nsc create account database
[ OK ] generated and stored account key "ADLKTPY4MPF7JPF3N7C4TWSOU24ZD5XFQ573LKSD5GVMWPIWFL2LAPTT"
[ OK ] added account "database"

vscode ➜ /tmp $ nsc create account customerA
[ OK ] generated and stored account key "AA4XIPKG4D7O33A3HPTWQC7UZMQQAVQIPBVVEY2PUOHK27OOMVTSQ7HE"
[ OK ] added account "customerA"

vscode ➜ /tmp $ nsc create account customerB
[ OK ] generated and stored account key "ABJX476VE7NKC5IBBNEWAVAWNNXW3W7P3WBP22QYZ2EHAQK73O27CJGK"
[ OK ] added account "customerB"

vscode ➜ /tmp $ nsc create export -i
? select account customerA
? export type stream
? subject streams.database
? name streams.database
? private stream Yes
[ OK ] added private stream export "streams.database"

vscode ➜ /tmp $ nsc create export -i
? select account customerB
? export type stream
? subject streams.database
? name streams.database
? private stream Yes
[ OK ] added private stream export "streams.database"

Database account:

+--------------------------------------------------------------------------------------+
|                                   Account Details                                    |
+---------------------------+----------------------------------------------------------+
| Name                      | database                                                 |
| Account ID                | ADLKTPY4MPF7JPF3N7C4TWSOU24ZD5XFQ573LKSD5GVMWPIWFL2LAPTT |
| Issuer ID                 | OADEHIDYAUOICHPB7OZXT7YVQSPWK3AKAN4FG3KKMBCC2ITQTGI6OHPS |
| Issued                    | 2022-11-14 16:30:49 UTC                                  |
| Expires                   |                                                          |
+---------------------------+----------------------------------------------------------+
| Max Connections           | Unlimited                                                |
| Max Leaf Node Connections | Unlimited                                                |
| Max Data                  | Unlimited                                                |
| Max Exports               | Unlimited                                                |
| Max Imports               | Unlimited                                                |
| Max Msg Payload           | Unlimited                                                |
| Max Subscriptions         | Unlimited                                                |
| Exports Allows Wildcards  | True                                                     |
| Disallow Bearer Token     | False                                                    |
| Response Permissions      | Not Set                                                  |
+---------------------------+----------------------------------------------------------+
| Jetstream                 | Disabled                                                 |
+---------------------------+----------------------------------------------------------+
| Exports                   | None                                                     |
+---------------------------+----------------------------------------------------------+

Customer A:

+--------------------------------------------------------------------------------------+
|                                   Account Details                                    |
+---------------------------+----------------------------------------------------------+
| Name                      | customerA                                                |
| Account ID                | AA4XIPKG4D7O33A3HPTWQC7UZMQQAVQIPBVVEY2PUOHK27OOMVTSQ7HE |
| Issuer ID                 | OADEHIDYAUOICHPB7OZXT7YVQSPWK3AKAN4FG3KKMBCC2ITQTGI6OHPS |
| Issued                    | 2022-11-14 16:30:02 UTC                                  |
| Expires                   |                                                          |
+---------------------------+----------------------------------------------------------+
| Max Connections           | Unlimited                                                |
| Max Leaf Node Connections | Unlimited                                                |
| Max Data                  | Unlimited                                                |
| Max Exports               | Unlimited                                                |
| Max Imports               | Unlimited                                                |
| Max Msg Payload           | Unlimited                                                |
| Max Subscriptions         | Unlimited                                                |
| Exports Allows Wildcards  | True                                                     |
| Disallow Bearer Token     | False                                                    |
| Response Permissions      | Not Set                                                  |
+---------------------------+----------------------------------------------------------+
| Jetstream                 | Disabled                                                 |
+---------------------------+----------------------------------------------------------+
| Imports                   | None                                                     |
+---------------------------+----------------------------------------------------------+

+--------------------------------------------------------------------------------+
|                                    Exports                                     |
+------------------+--------+------------------+--------+-------------+----------+
| Name             | Type   | Subject          | Public | Revocations | Tracking |
+------------------+--------+------------------+--------+-------------+----------+
| streams.database | Stream | streams.database | No     | 0           | N/A      |
+------------------+--------+------------------+--------+-------------+----------+

Customer B:

+--------------------------------------------------------------------------------------+
|                                   Account Details                                    |
+---------------------------+----------------------------------------------------------+
| Name                      | customerB                                                |
| Account ID                | ABJX476VE7NKC5IBBNEWAVAWNNXW3W7P3WBP22QYZ2EHAQK73O27CJGK |
| Issuer ID                 | OADEHIDYAUOICHPB7OZXT7YVQSPWK3AKAN4FG3KKMBCC2ITQTGI6OHPS |
| Issued                    | 2022-11-14 16:30:13 UTC                                  |
| Expires                   |                                                          |
+---------------------------+----------------------------------------------------------+
| Max Connections           | Unlimited                                                |
| Max Leaf Node Connections | Unlimited                                                |
| Max Data                  | Unlimited                                                |
| Max Exports               | Unlimited                                                |
| Max Imports               | Unlimited                                                |
| Max Msg Payload           | Unlimited                                                |
| Max Subscriptions         | Unlimited                                                |
| Exports Allows Wildcards  | True                                                     |
| Disallow Bearer Token     | False                                                    |
| Response Permissions      | Not Set                                                  |
+---------------------------+----------------------------------------------------------+
| Jetstream                 | Disabled                                                 |
+---------------------------+----------------------------------------------------------+
| Imports                   | None                                                     |
+---------------------------+----------------------------------------------------------+

+--------------------------------------------------------------------------------+
|                                    Exports                                     |
+------------------+--------+------------------+--------+-------------+----------+
| Name             | Type   | Subject          | Public | Revocations | Tracking |
+------------------+--------+------------------+--------+-------------+----------+
| streams.database | Stream | streams.database | No     | 0           | N/A      |
+------------------+--------+------------------+--------+-------------+----------+

Adding the first import from customer A works:

vscode ➜ /tmp $ nsc add import -i
? select account database
? pick from locally available exports Yes
? select the export   -> streams.database [!]
? name customerA
? local subject ingest.customerA
[ OK ] added stream import "streams.database"

Adding the second for customer B import fails:

vscode ➜ /tmp $ nsc add import -i
? select account database
? pick from locally available exports Yes
? select the export   -> streams.database [!]
? name customerB
? local subject ingest.customerB
Error: account already imports stream "streams.database" from ABJX476VE7NKC5IBBNEWAVAWNNXW3W7P3WBP22QYZ2EHAQK73O27CJGK

However if we inspect the JWT we can see that in fact doesn't have any imports from customer A, despite that being the one we selected in the menu. The import is fromABJX476VE7NKC5IBBNEWAVAWNNXW3W7P3WBP22QYZ2EHAQK73O27CJGK which corresponds to customer B.

{
  "jti": "GBAT726L7GNTKTY6CU6VLDROAQJR2RRPSDV6NT7K7V5DRCT7FFTQ",
  "iat": 1668443449,
  "iss": "OADEHIDYAUOICHPB7OZXT7YVQSPWK3AKAN4FG3KKMBCC2ITQTGI6OHPS",
  "name": "database",
  "sub": "ADLKTPY4MPF7JPF3N7C4TWSOU24ZD5XFQ573LKSD5GVMWPIWFL2LAPTT",
  "nats": {
    "imports": [
      {
        "name": "customerA",
        "subject": "streams.database",
        "account": "ABJX476VE7NKC5IBBNEWAVAWNNXW3W7P3WBP22QYZ2EHAQK73O27CJGK",
        "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJlZDI1NTE5LW5rZXkifQ.eyJqdGkiOiI1Rko3WFBIT1NQT09YNVNYREZFMkFYUDZTRUFGNFNYRjRDUDdDTkFFMkJQNEUzMkQ0WVhBIiwiaWF0IjoxNjY4NDQzNDI4LCJpc3MiOiJBQkpYNDc2VkU3TktDNUlCQk5FV0FWQVdOTlhXM1c3UDNXQlAyMlFZWjJFSEFRSzczTzI3Q0pHSyIsIm5hbWUiOiJzdHJlYW1zLmRhdGFiYXNlIiwic3ViIjoiQURMS1RQWTRNUEY3SlBGM043QzRUV1NPVTI0WkQ1WEZRNTczTEtTRDVHVk1XUElXRkwyTEFQVFQiLCJuYXRzIjp7InN1YmplY3QiOiJzdHJlYW1zLmRhdGFiYXNlIiwia2luZCI6InN0cmVhbSIsInR5cGUiOiJhY3RpdmF0aW9uIiwidmVyc2lvbiI6Mn19.TZc0deXvrL2YsP7prIiBegablwBDdJXMubx7ysJuj8jTQMK0ch77OeuT1ExZ5GvQFC6naSG2rW75Xx2Jd00FDA",
        "local_subject": "ingest.customerA",
        "type": "stream"
      }
    ],
    "limits": {
      "subs": -1,
      "data": -1,
      "payload": -1,
      "imports": -1,
      "exports": -1,
      "wildcards": true,
      "conn": -1,
      "leaf": -1
    },
    "default_permissions": {
      "pub": {},
      "sub": {}
    },
    "type": "account",
    "version": 2
  }
}

No matter why I try, it seems to be trying to re-add the customer B export. This only occurs when using interactive mode so I'm assuming it's going something to do with the fact that both exports have the same name.

Workaround

Don't use interactive mode, use nsc generate instead

@dylanratcliffe Yea I can verify the issue - the interactive mode seems to be not selecting the right thing. On adding the first import, it selects the wrong account. - To unblock you:

  • Generate the activations for customerA and customerB, and then add those as imports to the database account:
> nsc list keys -A
+----------------------------------------------------------------------------------------------+
|                                             Keys                                             |
+------------+----------------------------------------------------------+-------------+--------+
| Entity     | Key                                                      | Signing Key | Stored |
+------------+----------------------------------------------------------+-------------+--------+
| example    | OD2QNB5CNPQOAEBB64MTAVCWCDLYRT2I4W5J627UBRFMFLD5NGMCSOUE |             | *      |
|  SYS       | AAKACZKAXZ6Y6KLU5IWHWGL7UDVEGNVRDVBW4HEV7D73QMABZGGDRSWN |             | *      |
|  SYS       | AACG44LPRGXA2IR7FQZNPWPOO4SUCNXFRKCD3POTFHHAH3B776EYTOYG | *           | *      |
|   sys      | UDET5GIEO3EHHFTQ27FJSEHOMBHNVXQGXNHAM7L7G4VSIUIKCUYXMJ5J |             | *      |
|  customerA | ABTKBYD4SNBU5MO5NU65DD3SVSCDZZGZBSJ6EWVSLV7L2PVGGOVHD5KK |             | *      |
|  customerB | ACNIS7UG444FLRSLWRNN2ASZLQDOTYIL3KOJHNP7HWROWR6LPXLRELZ7 |             | *      |
|  database  | AC33OTL6DMHIL6IBUAXTOUBYYJN7ELW4EMVFWG4MIUWUBA47O46YODXG |             | *      |
|  example   | AADW3BBQVNGPMZXV5EYLRBGSQBFMPVZ5GW4GGFUMKBNVZCF7HELY7WWC |             | *      |
|   example  | UCIS2MCJV4LLYYWVY3NKQH32JEKYQNECNLF5YBIZLNXHLLUKCFVB6C5I |             | *      |
+------------+----------------------------------------------------------+-------------+--------+


> nsc generate activation -a customerA -t AC33OTL6DMHIL6IBUAXTOUBYYJN7ELW4EMVFWG4MIUWUBA47O46YODXG -o /tmp/customerA
[ OK ] generated "streams.database" activation for account "AC33OTL6DMHIL6IBUAXTOUBYYJN7ELW4EMVFWG4MIUWUBA47O46YODXG"
[ OK ] wrote activation token to `/tmp/customerA`
all jobs succeeded
> nsc generate activation -a customerB -t AC33OTL6DMHIL6IBUAXTOUBYYJN7ELW4EMVFWG4MIUWUBA47O46YODXG -o /tmp/customerB
[ OK ] generated "streams.database" activation for account "AC33OTL6DMHIL6IBUAXTOUBYYJN7ELW4EMVFWG4MIUWUBA47O46YODXG"
[ OK ] wrote activation token to `/tmp/customerB`
all jobs succeeded
> nsc add import --token /tmp/fromA -s ingest.customerA
[ OK ] added stream import "streams.database"
> nsc add import --token /tmp/fromB -s ingest.customerB
[ OK ] added stream import "streams.database"

nsc describe account database
+--------------------------------------------------------------------------------------+
|                                   Account Details                                    |
+---------------------------+----------------------------------------------------------+
| Name                      | database                                                 |
| Account ID                | AC33OTL6DMHIL6IBUAXTOUBYYJN7ELW4EMVFWG4MIUWUBA47O46YODXG |
| Issuer ID                 | OD2QNB5CNPQOAEBB64MTAVCWCDLYRT2I4W5J627UBRFMFLD5NGMCSOUE |
| Issued                    | 2022-11-14 18:01:36 UTC                                  |
| Expires                   |                                                          |
+---------------------------+----------------------------------------------------------+
| Max Connections           | Unlimited                                                |
| Max Leaf Node Connections | Unlimited                                                |
| Max Data                  | Unlimited                                                |
| Max Exports               | Unlimited                                                |
| Max Imports               | Unlimited                                                |
| Max Msg Payload           | Unlimited                                                |
| Max Subscriptions         | Unlimited                                                |
| Exports Allows Wildcards  | True                                                     |
| Disallow Bearer Token     | False                                                    |
| Response Permissions      | Not Set                                                  |
+---------------------------+----------------------------------------------------------+
| Jetstream                 | Disabled                                                 |
+---------------------------+----------------------------------------------------------+
| Exports                   | None                                                     |
+---------------------------+----------------------------------------------------------+

+---------------------------------------------------------------------------------------------------+
|                                              Imports                                              |
+------------------+--------+------------------+------------------+---------+--------------+--------+
| Name             | Type   | Remote           | Local            | Expires | From Account | Public |
+------------------+--------+------------------+------------------+---------+--------------+--------+
| streams.database | Stream | streams.database | ingest.customerA |         | customerA    | No     |
| streams.database | Stream | streams.database | ingest.customerB |         | customerB    | No     |
+------------------+--------+------------------+------------------+---------+--------------+--------+

Yeah verified that the nsc generate workaround works. Which is actually fine for me since that's what my automation uses anyway 👍

Fixed.