2023: Not Bad

I don’t usually do annual letters or year-end reports to brag about my accomplishments or complain about life’s burdens. But this time I am going to blow my own horn shamelessly. I could invoke the excuse that I am trying to demonstrate that even at the age of 65, you can have new experiences, learn new shit, and do cool things that you had hitherto never imagined — the way retirement is supposed to be. But… nah, fuck that.

The so-called TLDR

In 2023, in my third year of retirement, I studied (and learned some) Brazilian Portuguese; spent a couple weeks in Brazil; traveled to British Columbia; published more writing than I had in years; made my theatrical debut, as the Fool in Shakespeare’s Twelfth Night, no less; acted in a Halloween-themed immersive theatrical experience, playing the Grim Reaper; and performed as singer/guitarist in public a few times. Although I would have done all this for free, I got paid for acting and music-making. The compensation, though nominal, came as a deeply satisfying surprise; I had never dared imagine anyone ever paying me anything to act in a play or sing jazz standards, much less at this stage of my life.

Travel and Language Study

I did more international traveling than usual: first a trip to Vancouver, British Colombia in January; and in March I went to see a dear old friend who lives in Serra da Natividade in the state of São Paulo, Brazil. I had not seen this guy for 20 years during which we had little contact. The death in 2022 of a mutual friend, the musician Leon Atkinson, had served as a wake-up call. It was one of those bucket-list things: if you say you want to go see your friend Peter in Brazil some day, you better fucking do it because later may be too late.

One cool thing I did in preparation for the trip was study Brazilian Portuguese systematically for six months. I happen to have fluent Spanish already, which gives you not a free lunch, but a deeply discounted one. And I happen to have moved to the one region in the US where Spanish is not the second most spoken language. On the Cape and islands, it’s Portuguese. So after bemoaning but not doing anything about my ignorance of Portuguese for the first couple years of living here, with the added motivation of the upcoming trip, I finally got busy using two methods: the Pimsleur system, and talking with Brazilian people on the island. The latter is what I call street lessons. The learning process was not only fun but effective. My Portuguese still sucks, but it’s far better than nothing.

The Brazil trip was memorable. I also got around to other places to see people in 2023: my stepson and his girlfriend in the Vancouver area of British Colombia; my nephew and his family in Chicago; one of my stepdaughters in San Diego; my daughter in New Jersey; some very dear old friends in Connecticut.

Acting!

In the spring I succumbed to the temptation to audition for the Martha’s Vineyard Playhouse production of the Shakespeare comedy Twelfth Night. With exactly zero real theatrical experience, I felt a bit presumptuous, because this is not quite a community theater where everyone gets to participate who wants to. The first thing I did was check out a copy of the play from the library and read it with a view to finding a character who could conceivably be as old as me. I settled on the Fool, a natural fit: he says just the kind of shit I myself would say if I were more clever and speaking Shakespearean English. With a combination of merit and right-place-right-time luck — there being nobody else around who was better suited — I got the part.

The whole experience was amazing, from the first rehearsals all the way through to the end of the run. I never had more fun in my life. It was an honor to take the stage with this fabulous cast, and the show was extremely successful. Now that I have hit that crack pipe, you know I will be back for more.

The only fucked up part of the Twelfth Night experience was COVID. We had three cast members fall. The first went down during rehearsals but recovered in time for the opening. The second was our Countess Olivia who missed the first four shows. Our outrageously talented and heroic director (left of the Fool with the guitar) stepped into the role, learning it with less than a week’s notice. Then your humble servant fell to COVID in the middle of the run, and that selfsame director learned my part on two days’ notice, performing it five times before I was able to come back.

The second theatrical gig I had in 2023 — and the only other one on my résumé — was the Halloween-themed immersive theatrical experience that took place in the fall. Abby Bender comes up with wildly imaginative stuff, and in collaboration with other brilliant minds, puts together shows that are sui generis. Sometimes these shows are site-specific, informed by the history and architecture of the building where they happen. I won’t try to describe Granger Things. Let’s just say there were deer/dancers, farm animals, Halloween monsters, and more. I was the Grim Reaper.

Making Music

In 2023, I managed to get in front of audiences to sing jazz standards, accompanying myself on the guitar. This is remarkable only because just a couple years ago I would not have imagined it happening. I don’t consider myself a “real” singer. I just do it because sometimes I want to hear my favorite tunes performed, and I am the only person around to do the singing. After doing this for a while, I decided to inflict it on others.

Writing

In 2023, I wrote: an article for the World Socialist Website about some Massachusetts court interpreters’ struggle for a living wage; a rather boring article about the same thing for Proteus, official publication of the National Association of Judiciary Interpreters and Translators (NAJIT); a little essay for the NAJIT blog about the court interpreter as actor; and an op-ed for the Martha’s Vineyard Times challenging the lie that equates opposition to the Gaza genocide with antisemitism. That makes 2023 an unusually prolific year for me.

Anti-genocide Activism

When the Israeli state began its genocidal assault on Gaza following Hamas’ October 7 attack, I responded by doing what little I can do: writing, protesting, encouraging others to do the same. Some other islanders and I got together and founded an informal organization called CeasefireMV, also known as MVforPalestine. I slapped together a minimal website for us.

Distance Running

In my 50s I ran some marathons and ultramarathons, and numerous shorter races, getting respectable results in age-relative terms. Then I got older and stopped training seriously, but kept moving my feet about three times a week. Pace discipline has never come easily to me. But in 2023 I ran the smoothest, most disciplined and well-executed half marathon of my career, starting slow, then gradually accelerating all the way through. It was also one of the slowest. This race was a parable: at last the old man had the wisdom and self-control to execute a race plan, but was now too old to run his half marathon any faster than 2:01:43.

Please, admire these split times:

There was one day in the summer when I got up in the morning and won the men 60-69 age group in a local 5K race, then went to the amphitheater later the same day to perform in the Shakespeare show. What a stud!

Conclusion

Thank you for indulging this shameless exercise in self-aggrandizement. It was a rewarding and productive year. Being 65 can be a lot of fun. If you’re younger than that, I hope too you have this much fun when you get here.

interpreter as actor: an epiphany

Three years ago I retired from 30 years as a Spanish<>English court interpreter.  Before that I was a classical guitarist — a good one, but not so phenomenally good as to make a reasonable living out of it. At around age 30 I quit music and stumbled into court interpreting, thinking it might be an interesting and viable way to pay the bills.

All my life I have had a taste for adrenalin rushes and dopamine rewards of the kind you get from things like performing music on a stage, or skydiving, to which I was addicted for 10 years. I discovered that interpreting in open court, especially in scenarios like witness interpreting, is a performance before an audience, and that it provided enough challenge, pressure and excitement to satisfy the adrenalin junkie in me.

A lot of proceedings are largely scripted. I once worked with a defense attorney who, when prepping his client for a plea, spoke of when we go on stage — an expression I adopted and used forever thereafter.

Properly trained interpreters use the same grammatical person as the person whose words they’re interpreting, and in so doing, they are in a sense assuming the identity of that person. Most of us, at least to some degree, reproduce tone and expression, the better to convey the meaning as we understand it.

Often the outcomes in criminal proceedings are all but foregone conclusions, as if preordained, written in a script. Spoiler alert! The verdict is:  guilty.

I have rarely encountered any discussion in the professional literature, online forums or anywhere, about how we interpreters and translators, like actors, spend our days and make our livings expressing other people’s ideas and opinions rather than our own.  One exception I know of is the novel The Translator by the undeservedly little-known Ward Just, where this issue is mentioned in passing. No wonder so many of us spout off as we do when given the chance!  

Formulaic repetition; predictable outcomes; the ritualistic formality with which the players, if you will, play their parts in a courtroom; the way interpreters are constrained to reproduce other people’s thoughts, not their own; their use of expressivity to help get the meaning across:  in all these ways, the court interpreter’s job is like acting out a script. But this rather obvious notion of interpreter as actor was recently driven home to me with shocking clarity.

Last spring I succumbed to an urge to audition for the Martha’s Vineyard Playhouse’s production of the Shakespeare comedy Twelfth Night, and was cast as The Fool. Did I have any real theatrical experience? No. But the director liked my audition, and my musical abilities were useful to the production. Staged in the summer in an outdoor amphitheater, the show was extremely successful and well received. The other cast members were superb. I never had more fun in my life. One thing I found remarkable about this marvelous experience was how completely natural it felt to be on the stage, acting in a play. I have always had my attention-seeking, narcissistic, histrionic tendencies. Even so, this felt unexpectedly, almost absurdly normal. Why?

A few weeks after the play closed, I served as interpreter for an unusual event. You may recall news reports from September 2022 about the Venezuelan migrants whom Florida’s Governor Ron DeSantis used as pawns in his criminal political stunt, conning them with false promises into boarding a plane bound for Martha’s Vineyard. With no warning whatsoever, members of the local community immediately mobilized to provide services and support. Not only were our unexpected guests well cared for; the same people who handled last year’s surprise invited our Venezuelan friends back to the island for a reunion to mark the one-year anniversary. I was asked to interpret for a ceremonial event — my first time interpreting before an audience in more than three years. When there came a pause in my part of the action long enough for my mind to wander, it dawned on me: I had worked as an actor for 30 years! Of course it felt normal, natural, indeed familiar to perform in a play.

No, doing court interpreting and doing Shakespeare are not the same. It may not be just one easy step for all interpreters to move from the former to the latter. But are not interpreters located on a continuum that includes almost everyone? At one end, the only people who are their pure, authentic selves all the time are infants (and maybe, people with certain mental disorders); at the other extreme, actual actors. Virtually all of us, to some degree, go through life acting out our various roles. In their professional lives, interpreters are located especially close to the actor end of the spectrum.

As Shakespeare’s character Jaques says in As You Like It:

All the world’s a stage,
And all the men and women merely Players;
They have their exits and their entrances,
And one man in his time plays many parts[…]

* * *

sunshine squash soup: a recipe

My wife and I signed up for one of those deals where you pay a local farm up front and then, for the rest of the season, you stop by weekly to collect your hefty basket of quality produce. The good/bad news with these arrangements is that you sometimes find yourself under pressure to make use of vegetables that are unfamiliar, and which you would have walked right past if you’d been shopping in a store. Such was the case with a big-ass sunshine squash we recently got, one of those varieties with a hard thick skin that you’d be a fool to take on with a vegetable peeler. One recipe recommended roasting the squash in an oven and letting it cool before continuing to fuck with it. I decided it would be fun to use this idea for a soup, and began improvising with what was in our kitchen. I didn’t measure anything; all quantities are approximate. You may wish to use less or more stock depending on whether you have a moderate amount of squash or a shit-ton. And if you want to substitute another squash variety like butternut, this should work brilliantly, but you won’t need to roast it. I’d suggest preparing the aromatics as described below, then cutting the squash up into chunks and braising it in the stock until it’s soft enough to mash.

Preparation time: Over two hours from start to finish, much of it unattended.

Ingredients:

  • a large sunshine squash, buttercup squash, or similar
  • olive oil, about 3 tbsp
  • 1 heaping tbsp mintzed [sic] garlic
  • 1 heaping tbsp mintzed [sic] ginger
  • 1 tbsp cumin
  • 1 medium onion, diced
  • salt and fresh ground pepper
  • 1/2 tsp (or to taste) hot pepper flakes
  • 4 cups vegetable (or chicken) stock
  • 1 28-oz can of chick peas (or canellini beans), rinsed and drained
  • (optional) fresh parsely for garnish

Step One With a fork, poke some holes in the squash in several places, put it in a roasting pan with perhaps an inch of water. Roast the squash in a 350° oven for about an hour, until it yields to a fork. Then take it out and let it cool until you can handle it comfortably. Next, remove the stem, cut it in half, and remove the seeds. Use a knife to peel off the skin (this is the most tedious part of the project). Break up the squash — or let it fall apart — into chunks approximately the size of your fist or smaller.

Step Two In a large pot, heat the olive oil, then drop in the garlic and ginger and cook briefly, until they are sizzling and fragrant — about 20 seconds. Then put in the onion and cook, stirring occasionally, until the onion is soft.

Step Three Add the stock, squash, hot pepper flakes, cumin, and salt and pepper to taste. Stir it up and let it cook at a steady simmer, partially covered, for about 15 to 20 minutes. The objective is to let the flavors blend and get the squash very soft.

Step Four Use a potato masher to mash the squash into a liquid, stir it all up and adjust your seasonings if need be. Then add the beans, stir, and cook a bit longer to let the beans warm up.

Step Five You’re all done, unless you want to pretend you’re a restauranteur. If so, garnish with 17 cents worth of parsley and imagine yourself charging $16 instead of $9 for a bowl of soup.

The result was so ridiculously delicious that I felt compelled to write it up as a recipe and share it. If you cook this, feel free to tell us in the comments how it turned out and what good tweaks you introduced, if any.

Memo to God

To: The Supreme Being
From: HR Department
Subject: Immediate termination

Dear God:

This is to advise You that Your employment is terminated effectively immediately. You are hereby ordered to leave the premises at once.

Do not let the door of Your creation hit You in Your divine ass on the way out.

Very truly Yours,

Human Resources Department

On Getting Old

I would like to say that as I approached my 60th birthday, my attitude was one of equanimity, gratitude, all that wisdom bullshit.  The fact is that I was only partially successful in getting my head around this milestone. Any way you spin it, 60 is not young — unless, perhaps, you’re talking about a Supreme Court Justice, or the conductor of a world-class orchestra. Let’s face it: I am a lot closer to death than I was a few decades ago. My future is a lot shorter than my past. Of course, being dead is perfectly safe. Mark Twain is said to have said that he wasn’t the slightest bit worried about death because he had been dead for billions of years before he was born, and had suffered not the slightest inconvenience. That’s a great line, easy to agree with. Easy to talk the talk. But walking the walk: I admit that it freaked me out a bit to be walking down the street one day and suddenly noticing I was over 60. What is this,  some stupendous existential joke?

I considered sharing a few of these reflections in a blog post, but did not for a variety of reasons. One is that I procrastinate; another is that I expect no one to be interested in my bloviations. But I’ve overcome the first obstacle by delaying for a year and a half, sufficient even for a world-class procrastinator. As for the second, well, fuck it. Moreover, the urge to write was revivified the other day when something abruptly shifted inside my head.

Standing in my house, in a room,  staring into space, not doing whatever it was I was supposed to be doing (when you have the Attention Deficit Disorder, this happens a lot, irrespective of your age), it dawned on me that in the spring I would be 62 years old. And rather than feeling the clutch of fear, I felt elation. Sixty-two! How cool is that?

Sixty-two years old, and not only have they yet to put a toe-tag on me —  I am healthy. I’ve done quite a number things I wanted to do in this life, been involved in rewarding relationships with fascinating people, and have had a lot of fun. I’ve paid some dues, but on balance, this has unquestionably been a good run — and it ain’t over yet. I’ve landed in a good place, thanks to a modicum of discipline, a few wise decisions and not too many disastrous ones, and a lot of luck.

Granted, there’s a substantial chance that I will progress from old to very old, hence frail and sick, maybe lonely and depressed. Maybe the dementia will get me. That will surely suck, and I may well change my tune at that point (assuming the cognitive wherewithal). But in the meantime, I’ve realized moving through my 60s is nothing to complain or get upset about — quite the contrary.

I have noticed in myself an increased tendency towards retrospection as I’ve gotten older, and wonder if others around my age have the same experience. It would make sense that you would turn your gaze towards the past when you’ve arrived at the point, as noted above, where your future is a lot shorter than your past. There’s more of the latter and less of the former to think about. Life is like this at any age — you experience shit, then process it and hopefully learn something, even if not consciously. Maybe in the final stretch we do this, but on a greater scale. Now comes the time for reflection, grand summaries, conclusions, and — dare I say it? — deeper levels of understanding. Understanding what, you reasonably ask? The way in which events and interactions with others have unfolded in your life. Or, to put it more simply, at the risk of sounding sententious:  life.

 

Can you keep a secret? Integrating HashiCorp Vault with a Zend Framework Application

Why do we hash user passwords in our databases? So that if bad actors somehow gain access to our database, they will have a hard time stealing our secrets. But suppose we need to securely store other sensitive data in our database? Encrypt it. But how do we go about that? Assymetric, public/private key encryption with PGP would undoubtedly be the best way to go, but in the case at hand, it’s too impractical. Faced with this situation, I reasoned that symmetrical encryption was the next best option:  use one key for both encryption and decryption. But how to store the encryption key securely? As a plain text file sitting on the same server as the database username and password? Which, by the way, are also sitting there in plain text, if not in plain sight?

Disclosures, Disclaimers, Excuses

Now that I have your attention, a quick digression. I am not a security expert — I just try to pay attention to those who are. So please, use your own judgment at your own risk yadda yadda yadda. Moreover, I’m not even officially a web application developer. My job title has nothing to do with that. Long story short: I stumbled into coding some 20 years ago because in my workplace we could find no software, commerical or otherwise, that met our needs in managing a busy federal court interpreters office. So we (OK, I) rolled our own, and have been rolling ever since. Now I’m working on the next iteration of our great project, using Zend Framework 3 and Doctrine, and that’s the context in which this security problem arises.

Wandering back to our main topic: we need to store some sensitive data of contract court interpreters in a database, we want to encrypt it symmetrically, and we need to keep the secret encryption key secret.

Hashicorp Vault to the rescue

The very clever people at Hashicorp generously provide, among other things, a secret-management tool aptly named Vault. As their website puts it,

Vault is a tool for securely accessing secrets. A secret is anything that you want to tightly control access to, such as API keys, passwords, certificates, and more. Vault provides a unified interface to any secret, while providing tight access control and recording a detailed audit log.

The use of Vault is a complex subject, and the following discussion is no substitute for the documentation. We should just point out that secrets (yes, that’s the technical term) can be stored in several different types of storage backends, and authentication can happen by way of a number of different authentication backends. These things are identified and accessed by way of paths similar to a filesystem. And that unified interface mentioned above is an HTTP API. You talk to Vault by sending HTTP requests with an authentication token in your request headers, and get JSON responses. Of course, this makes it a snap for applications to communicate with Vault with the language of your choosing.

The challenging part is devising a good security model, and there is a vast — if not to say baffling — array of choices and decisions to be made. I’m still not convinced my current solution is the best, so it’s subject to change. But let’s step through it as it is at the moment. Of course, you’ll first need to install and configure and run Vault, and they make that pretty damn easy. (Though you do have to decide what machine(s) to put it on. There’s replication and high availability and all that sexy stuff for large-scale deployments. Ours happens to be a modest configuration, involving a small set of users behind our organization’s firewall.)

Creating Policies

In Vault, you create authentication tokens that have policies attached to them, determining what the bearer of the token is allowed to do. I want our authenticated application not to be authorized to read our ultimate secret, but to grant an auth token bound to a policy that does allow it. So we need a policy for reading the secret. We also need a policy for creating the token that’s attached to the policy for reading the secret. Sound complicated? Don’t worry: it is! But the underlying principle is a basic one:  grant access that is as permissive as necessary, and no more. So I took out my quill and wrote policies, thus:

read-secret.hcl

path "secret/data" {
  policy = "read"
}

create-token.hcl

path "auth/token/create/read-secret" {
	policy = "write"
}

Incidentally, that .hcl extension you see refers to Hashicorp Configuration Language. It’s a lot like JSON and you’ll pick it up immediately. Then, after logging into Vault with sufficient privileges, we wrote our policies to Vault via its CLI:

vault policy-write read-secret read-secret.hcl

and

vault policy-write create-token create-token.hcl

and finally, the rather more esoteric one:

vault write auth/token/roles/read-secret allowed_policies=read-secret

which magically allows the “role” to bestow access to something that the role itself cannot access.

Authenticating the application

As implied above, I decided Step One should be that not the user but the application authenticates itself against Vault using the TLS backend. To that end, I created my certificates (thank you, https://jamielinux.com/docs/openssl-certificate-authority/ for help with that), stored them in Vault,

vault write auth/cert/certs/web display_name=web policies=create-token \
	certificate=@/path/to/your/cert.pem 

and tested it out with the Vault cli,

vault auth -method=cert -client-cert=/path/to/your/cert.pem \
    -client-key=/path/to/your/key.pem

then with the HTTP API using our good friend curl. By the way, before thinking too much about integration with ZF, I followed the same procedure with all this token stuff until I was able to go from zero to reading the secret (encryption key) from the command line. I predicted (correctly!) that the heavy lifing was setting up the Vault stuff, and getting it to play well with ZF would be more like fun than work.

Getting a token for getting the secret

After the previous command, now that we’re authenticated via TLS, we can go

vault token-create -role=read-secret

and get a response something like

Key            	Value
---            	-----
token          	ef2fb0d1-1644-937f-5326-3c6270abc3ba
token_accessor 	522c0a9d-7897-a670-e511-650d37ea6d20
token_duration 	768h0m0s
token_renewable	true
token_policies 	[default read-cipher]

Getting the secret

And finally, authenticate with the token we just got:

vault auth ef2fb0d1-1644-937f-5326-3c6270abc3ba

and go for the gold

vault read secret/data

resulting in

Key             	Value
---             	-----
refresh_interval	768h0m0s
cipher          	b862600aaeba7c4ccd74006d2e616083ffb7031a3b088e743080bcf32e90f3b4

and that “cipher” you see is the encryption key for encrypting/decrypting our sensitive database fields, a step we will perform in our PHP application.

In all honesty, it’s a bit more complicated than this because we are going to be using response wrapping. When a client sends the header so indicating, the response is not the thing requested, but another auth token with which you can get the thing requested. And that token is a single-use token:  use it once and then it’s revoked. You can also limit the time-to-live on this token, so that whether it gets used or expires, it is not going to be hanging around for long as a valid token. This exemplifies the Vault (and general security) principle of limiting the exposure of a secret.

Plugging it into ZF

The front end

At last, the fun part. (Not to say that Vault isn’t loads of fun — it absolutely is! But after dealing and struggling with something unfamiliar, it’s comforting like a warm bath to return to the familiar, isn’t it?) I decided that this application would have its Vault capabilities in a separate module to make it easy to enable or disable. If it’s disabled, they simply don’t get to work with sensitive data. Let’s work from the front end to the back. The form has a good number of fields, but the ones we’re concerned with look like this:

because there’s no reason to expose this data if they don’t ask. The encrypted values are tucked away as hidden fields. When they click those lock thingies, we display a modal dialog inviting the already-authenticated user to re-authenticate (in case they load the form, wander off to the bathroom, and just then an identity thief comes up to their workstation). A couple of Javascript xhr calls later, if all goes well, the dialog goes away and these fields are re-populated with the decrypted values.

The Controller

And the above-mentioned xhr sends a POST request containing the encrypted values to /vault/decrypt, a route mapped to this action method in our module/Vault/src/Controller/VaultController.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
        public function decryptAction()
    {
        $params = $this->params()->fromPost();
 
        try  {
 
            $key = $this->vaultService->getEncryptionKey();
            $cipher = new BlockCipher(new Openssl());
            $cipher->setKey($key);
            $decrypted = [
                'ssn' => $cipher->decrypt($params['ssn']),
                'dob' => $cipher->decrypt($params['dob'])
            ];
            return new JsonModel($decrypted) ;
 
        } catch (VaultException $e) {            
             return new JsonModel(['error'=>$e->getMessage()]);
        }
    }

The part involving Vault gets our encryption key, and it’s a one-liner. The next bit simply makes use of zend-crypt to take care of decryption.

You notice $this->vaultService. That’s a dependency injected via the constructor, so there’s a factory which pulls it from the container. Boring, so we’ll skip that part. Let’s have a look at the module’s module.config.php (ooh, exciting!)

Configuration

<?php
namespace SDNY\Vault;
use Zend\Router\Http\Literal;
 
return [          
    'vault' => [           
        // override these with a local configuration
        'vault_address' => 'https://vault.example.org:8200', 
        'sslcafile'     => '/usr/share/ca-certificates/ca-chain.cert.pem',
        // these settings must match the configuration set in Vault
        'ssl_key' => '/path/to/your-private-key.key.pem',
        'ssl_cert' => '/path/to/your-cert.pem',    
        'path_to_secret' => '/path/to/your/secret', // including leading slash
        // but do not change this adapter
        'adapter'       => 'Zend\Http\Client\Adapter\Curl',       
    ],    
    'service_manager' => [
        'factories' => [
            Service\Vault::class => Service\Factory\VaultServiceFactory::class,           
        ]
    ],
    'controllers' => [
        'factories' => [           
            Controller\VaultController::class => Controller\Factory\VaultControllerFactory::class,
        ]
    ],   
];

So the module’s config sets some default/dummy values, with the expectation that they will be overridden by a local configuration file called something like config/autoload/vault.local.php, consistent with the ZF convention. No reason to put this in a public repository.

The Vault service

We have a VaultServiceFactory that injects all that config for us when it instantiates our VaultService, which is what does the talking to Vault.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
<?php
/**
 * module/Vault/src/Service/Vault.php
 */
 
namespace SDNY\Vault\Service;
 
use Zend\Http\Client;
 
 
/**
 * Extension of Zend\Http\Client for communciating with Hashicorp Vault
 * 
 * The purpose is enable us to store sensitive data in MySQL using symmetrical
 * encryption while avoiding having to store the encryption key in plain text 
 * anywhere at any time. All the configuration has to be correctly set before 
 * instantiation. Error-checking is left up to the consumer.
 * 
 */
 
use Zend\EventManager\EventManagerAwareInterface;
use Zend\EventManager\EventManagerAwareTrait;
 
class Vault extends Client implements EventManagerAwareInterface {
    use EventManagerAwareTrait;
 
    protected $events;
 
    /**
     * mapping of string keys to CURL integer constants
     * 
     * we need this because if a config array key is an integer
     * unfortunate things happen when the framework merges the configs
     * 
     * @var array
     */
    private static $curlopt_keys = [
        'ssl_key' => \CURLOPT_SSLKEY,
        'ssl_cert'=> \CURLOPT_SSLCERT,        
    ];
 
    /**
     * vault authentication token
     * 
     * @var string
     */
 
    private $token;
 
    // some more instance variables omitted for brevity
 
    /**
     * constructor
     * 
     * @param array $config
     */
    public function __construct(Array $config) {
 
        $this->vault_address = $config['vault_address'] . $this->prefix;
        $this->path_to_secret = isset($config['path_to_secret']) ? 
            $config['path_to_secret'] : null;
        $curloptions = [];
        foreach ($config as $key => $value) {
            if (key_exists($key, self::$curlopt_keys)) {
                $curloptions[self::$curlopt_keys[$key]] = $value;
            }
        }
        $config['curloptions'] = $curloptions;       
 
        parent::__construct(null, $config);
        $this->getRequest()
            ->getHeaders()
            ->addHeaderLine('Accept: application/json');
    }
 
    // some setters/getters omitted for brevity
 
 
    /**
     * checks response for errors
     * @param Array $response
     * @return boolean true if error
     */
    public function isError(Array $response) {
        return key_exists('errors',$response);
    }
 
    /**
     * resets request, response, etc, and restores
     * request header for JSON responses
     * 
     * @return \SDNY\Vault\Service\Vault
     */
    public function reset()
    {
        parent::reset();
        $this->getRequest()
            ->getHeaders()
            ->addHeaderLine('Accept: application/json');
        return $this;
    }
 
    /**
     * attempts Vault TLS authentication
     * 
     * this will attempt to authenticate using TLS certificates, which have to 
     * have been installed and set in our configuration up front. 
     * 
     * @link https://www.vaultproject.io/docs/auth/cert.html
     * 
     * @return Vault
     * @throws VaultException
     */
    public function authenticateTLSCert($options = [])
    {
        $this->setMethod('POST')
            ->setUri($this->vault_address .'/auth/cert/login')
            ->send();        
        $response = $this->responseToArray($this->getResponse()->getBody());
        if ($this->isError($response)) {
            $this->getEventManager()->trigger(__FUNCTION__, $this, []);
            throw new VaultException($response['errors'][0]);
        }
        $this->token = $response['auth']['client_token'];
 
        return $this;
    }
 
    /**
     * Attempts to acquire access token that is authorized to read the cipher 
     * we use for symmetrical encryption/decryption of sensitive Interpreter 
     * data.
     * 
     * @return Vault
     * @throws VaultException
     */
    public function requestCipherAccessToken()
    {
        $this->getRequest()->getHeaders()
                ->addHeaderLine("X-Vault-Token:$this->token")
                ->addHeaderLine("X-Vault-Wrap-TTL: 10s");
        $endpoint = $this->vault_address . '/auth/token/create/read-cipher';
        $this->getRequest()->setContent(json_encode(
               [
                // maybe reconsider these settings
                'ttl' => '5m',
                'num_uses' => 3,
               ]
        ));
        $this->setMethod('POST')->setUri($endpoint)->send();
        $response = $this->responseToArray($this->getResponse()->getBody());
        if ($this->isError($response)) {
            $this->getEventManager()->trigger(__FUNCTION__, $this, [
                'message' => 'failed to get token for cipher access'
            ]);
            throw new VaultException($response['errors'][0]);
        }        
        $this->token = $response['wrap_info']['token'];
        return $this;             
    }
 
 
    /**
     * unwraps a wrapped response and returns it as an array
     * 
     * @param string $token
     * @return array
     */
    public function unwrap()
    {
        $this->reset();
 
        $endpoint = $this->vault_address . '/sys/wrapping/unwrap';
        $this->setAuthToken($this->token);
        $this->setMethod('POST')->setUri($endpoint)->send();
 
        $response = $this->responseToArray($this->getResponse()->getBody());
        if ($this->isError($response)) {
            $this->getEventManager()->trigger(__FUNCTION__, $this, [
                'message' => 'failed to unwrap response'
            ]);
            throw new VaultException($response['errors'][0]);
        }
        if (isset($response['auth'])) {
            $this->setAuthToken($response['auth']['client_token']);
        }        
        return $response;      
    }
 
    /**
     * requests response-wrapped encryption key
     * 
     * @param string $token authentication token
     * @return Vault
     * @throws VaultException
     */
    public function requestWrappedEncryptionKey()
    {
        if (! $this->path_to_secret) {
            throw new VaultException('path to secret has to be set before calling '.__FUNCTION__);
        }
        $endpoint = $this->vault_address . $this->path_to_secret;        
        $this->getRequest()->getHeaders()->addHeaderLine("X-Vault-Wrap-TTL: 10s");
        $this->setMethod('GET')->setUri($endpoint)->send();
        $response = $this->responseToArray($this->getResponse()->getBody());
         if ($this->isError($response)) {
            $this->getEventManager()->trigger(__FUNCTION__, $this, [
                'message' => 'failed to get wrapped encryption-key response'
            ]);
            throw new VaultException($response['errors'][0]);
        }
        $this->setAuthToken($response['wrap_info']['token']);
        return $this;  
 
    }
    /**
     * gets encryption key.
     *
     * convenience method that wraps the several 
     * steps into one.
     *
     * @param string $token authentication token
     * @return string
     * @throws VaultException
     */
    public function getEncryptionKey()
    {
        $this->authenticateTLSCert()
                ->requestCipherAccessToken()
                ->unwrap();
        $this->requestWrappedEncryptionKey();
        $key = $this->unwrap()['data']['cipher'];
        return $key;
 
    }
 
    /**
     * sets Vault authentication token header
     * and instance variable
     * 
     * @param string $token
     * @return \SDNY\Service\Vault
     */
    public function setAuthToken($token)
    {
        $this->getRequest()
            ->getHeaders()
            ->addHeaderLine("X-Vault-Token:$token");
        $this->token = $token;
        return $this;
    }        
 
    /**
     * converts json to array
     * 
     * @param string $json
     * @return Array
     */
    public function responseToArray($json) {
 
        return json_decode($json,true);
    }
 
    /**
     * attempts user/password authentication
     * 
     * this will attempt to authenticate user against Vault's 
     * userpass auth backend. NOTE: looks like we won't be using this auth 
     * method after all, so this method is not currently used.
     * @link https://www.vaultproject.io/docs/auth/userpass.html
     * 
     * @param string $user
     * @param string $password
     * @return array Vault response as array
     */
    public function authenticateUser($user,$password)
    {
        $uri = $this->vault_address . "/auth/userpass/login/$user";
        $this->getRequest()->setContent(json_encode(['password'=>$password]));
        $this->setUri($uri)->setMethod('POST')->send();
 
        return $this->responseToArray($this->getResponse()->getBody());  
 
    }
 
}

This Vault service extends Zend\Http\Client because it basically is a specialized http client. The general pattern is that most of these methods attempt to get the token we need, store it in $this->token, and return $this so the lazy coder using the class can save some keystrokes.

We make use of the handy Zend\EventManager\EventManagerAwareInterface and Zend\EventManager\EventManagerAwareTrait and do a fair amount of $this->getEventManager()->trigger(). It’s most definitely a work in progress, but by the time this project is done (or pretty close) there are going to be event listeners responsible for logging things and generally paying attention. On the Vault side, I plan to (figure out a way to) monitor the audit log with the ultimate goal of trying to detect a possible breach and hit the panic button.

So we’ve demonstrated decryption, how about encryption? Coming soon! But as you can see, it will be straightforward.

Further thoughts on Vault and PHP Applications

Remember we started out with a reference to the practice of storing database credentials in plain text? Vault provides a database secret backend so you can avoid doing that. Vault also has a very straightforward user/password authentication backend that makes it tempting to consider implementing a Zend\Authentication\Adapter\AdapterInterface that uses it.

All of this is to say that in terms of security, I think Vault offers us ways to take Zend Framework applications, and PHP applications generally, to the next level.

Conclusion

As noted at the beginning, this solution to my challenge of keeping our encryption key secure may not be the best possible. But it’s a start. The first objective was to avoid leaving our secret lying around in plain text, and this accomplishes that. My holy grail is to make it so that even in a worst case scenario, where an attacker gains root access to the machine where this application is installed, my precious social security numbers and dates of birth would still not be compromised. Like anything, this model is not guaranteed bullet-proof against a breach that severe, but again, it’s a start.

Hopefully this demonstrates that once you have Vault going, it’s quite easy to integrate with your ZF application. As a personal note, I would add that this is actually my debut blogging about Zend Framework, and I do feel a little self-conscious about presuming to address an audience with so many badasses in it. Stage fright notwithstanding, I am truly interested in hearing your comments, so please feel free.

References

Remembering Dan B

The objective connection between Danny and me is that we are stepbrothers: his father and my mother were married to each other for over 40 years. They met when both were employed at the U.S. Naval Observatory in Washington, D.C.

When I first met him, I was 13 and Dan was 17. Those days were very much the latter phase of the 1960s, culturally speaking. I was then (already) keenly interested in doing drugs and being cool. Dan was the embodiment of all that I aspired to: a cool hippie dude. Complete with long hair, beard, and musical abilities, he was what we used to call “far out” without irony. He was like an older brother and I attached to him immediately.

Our relationship was episodic. For a time in the 1970s we lived together — indeed, in the same room — in La Serena, Chile, where his father directed the Cerro Tololo observatory. In 1982-1983, we happened to overlap again in Tucson when I was graduate student in guitar at the University. After that phase, we would cross paths from time to time owing to the family connection. He showed up for the wedding festivities when I got married (the first of two times) in Puerto Rico in 1994. A few times we coincided while visiting his dad’s/my mom’s home in La Serena and later in Vero Beach, Florida.

Danny was what’s known as a survivor. Of course the past tense is appropriate here — he survived until he didn’t, and if he were here now he’d probably laugh at some grim joke along those lines. But my point is that he overcame some fantastically bad breaks. He was dealt a shitty hand, with mother and brother both suffering from severe mental illnesses and a sister that was… kind of strange, if I may be forgiven for saying so. His dad, my stepdad, was remarkable: an accomplished astronomer and unfailingly loving and generous person. Except that he didn’t much care for dealing straight on with the interpersonal — not an uncommon characteristic, especially among men, especially men of his generation. So he took off for Washington D.C. to take the job at the Naval Observatory, and left Danny at age 15 to deal alone with his profoundly dysfunctional family. And deal with it he did. He got through all that and more, and led a life doing a great many interesting things that he wanted to do, rich in relationships with interesting people.

Truth be told, most of my memories of the times I spent with him are pretty banal, but entirely pleasant. There was good chemistry among our parents and us, and we enjoyed many a happy evening as a merry quartet, eating and drinking well and enjoying lots of long hard laughs. I have a mental picture from one afternoon at a beach in Chile. We waded into the surf and threw a frisbee back and forth, making heroic diving catches of errant throws — the sort of maneuver you might expect from a serious baseball player — but falling painlessly into the water instead of hitting the ground. It was funny, really funny in a physical-comedic way that’s impossible to describe. I have a vivid image of him emerging from the water after one those moves, laughing, laughing…

Now this is part where I make my presentation more compelling by choking up and shedding a tear or two. Note to Danny: that’s another laugh line I think you’d have found amusing.

And now I recover and continue with another fun memory, probably from that same period of time when we spent a couple of weeks in La Serena. We played several games of chess, winning and losing more or less evenly. It was the last night — one of us, I forget who, was traveling back to the U.S. the next morning. So we sat down for a final chess game and abused a bottle of Bailey’s Irish Creme, of all things. That isn’t a very high-alcohol drink and we were both fairly robust drinkers, so we got a little silly but not excessively drunk. The laughter, conversation and chess lasted through the night. The game finally ended in a draw, an outcome that pleased us both.

It is common to canonize people when they die, but there’s no need for that here. Dan definitely had his peculiarities, as do we all in one form or another. He was also a truly extraordinary person, talented and intelligent in a multiplicity of ways, an independent and original thinker, with a sense of humor surpassed by no one. Cliché though it sounds, he lived a full life. But he also did an exceptionally courageous job of dying, from what I can tell. One thing I regret about not attending his memorial in person is not being able to hear more about this from those who were with him at the end. He went out with equanimity, dignity and grace. At times like these I like to quip that dying is so very fashionable. Everyone does it! Those who have not done it yet will get their chance in due course. When my great moment comes I hope to emulate his example.

There is a powerful line in a novel by the writer Haruki Murakami, where two of his characters are in the presence of another who has just died. It reads: he had just accomplished the profound, personal feat of dying.

Good bye, brother Dan. You have accomplished the profound, personal feat of dying.

You’ve Got Us Under Your Skin

This little ditty, to the tune of I’ve Got You Under My Skin, was created for the 2013 Courthouse Follies. It is disrespectfully dedicated to the NSA.

They’ve got us under their skin
They’ve got us deep in the heart of them
So deep in their heart, we’re really a part of them
They’ve got us under their skin

We’re always listening in
Their emails and phone calls and texts always go down so well
To our data centers where they’re lovingly stored so well
[addressing audience from here on]
You’ve got us under your skin

We’ll sacrifice anything, come what might
For the sake of stoking up fear
We violate every constitutional right
That we still claim to hold dear

Don’t you know little fools, you can never win?
Forget legality
Wake up to reality
If you really do value privacy
You should stop before you log in
‘Cause you’ve got us under your skin

Is social inequality inherent to human society?

In an exchange of comments Facebook the other day, somebody said:

“Capitalism doesn’t create inequality, if it did there wouldn’t be inequality existent in other economic systems which there most certainly is. Inequality is inherent to the human condition. We are not all equally capable or equally industrious so we will not enjoy equal results. There is no system that creates equality because equality doesn’t exist. It’s a fiction people choose to believe. Believe it if you will, but don’t tear down an economic system that provides you with the free time to indulge such fantasies. I’ll grant you that capitalism isn’t fair, but show me an economic model that produces more. I’ll take freedom over equality any day. Right now, we have neither.”

Hereafter I’m using the second person to address the commenter.

Your remarks reflect such a strong attachment to capitalist orthodoxies that it is unlikely I can say anything to convince you, and there are so many misconceptions and fallacies that it’s hard to know where to begin. But I should try to make a couple points just for the record.

The fact that “other economic systems” — i.e., other than capitalism — have resulted in social inequality (or were likewise based on it, as with slavery and feudalism) in no way proves that capitalism does not also produce inequality. More to the point, the data and the historical record are overwhelming. Few serious scholars, economists, etc. dispute that the global capitalist order has produced massive social inequality – even capitalists acknowledge this. The world’s most powerful, elite government officials, corporate executives and academics gather for their conference in Davos to wring their hands over the global social, economic and environmental crisis resulting from capitalism’s excesses. (And rightly so, because such a system not only morally reprehensible, but also unsustainable.). No, the great dispute is over the way forward.

Further, there really is no other economic system of consequence in the modern global economy, other than capitalism, hence nothing to compare except in historical terms. If you look at history, you can say slave-based and feudal societies were unequal, so that must be the human condition. But this too is fallacious; there is no basis in evolutionary biology, history, anthropology, or what have you, to conclude that capitalist, market-based forms of social organization are somehow genetically embedded in homo sapiens.

You seem to be confusing the Enlightenment-inspired ideal of equality, the notion of human and social rights, with the obvious fact of variation from one individual to another. Of course, some people excel more than others at sports, math, language, music — and some are just plain smarter than most of the rest of us. Some are “industrious,” some are boneheads and slackers. Is that any excuse for a system in which countless millions toil at slave wages while a handful of billionaires control the world’s resources?

Capitalism subordinates social need to private accumulation. Inequality is not just an unfortunate side effect; it’s an essential feature. Marx told you a long time ago that under capitalism, wealth tends to concentrate at the top at the expense of the many, and history has proven it. Yes, there have been booms, as in the post-Word War II period, when living standards in the U.S. rose generally —thanks to the fearless struggles of socialist-minded workers who achieved a few significant social reforms. The data is incontrovertible, however, that for the past three decades or so, wages have stagnated even while productivity has increased. Since the financial collapse 2008, of course, matters have gotten much worse for broad swaths of the population, while the tiny layer at the top enjoys a share of the national income not seen since the robber baron days.

These levels of inequality are wholly incompatible with democracy. You correctly state that right now we have neither freedom nor equality. But that is no mere coincidence. With these levels of inequality, social explosion is inevitable. The ruling class cannot permit freedom in the face of such instability; in order to maintain control, there has to be mass surveillance of the population (brought to you by the NSA), ruthless police violence, and an exaggerated threat of terrorism to incite fear.

You say don’t tear down an economic system that provides me with the free time to indulge my fantasies. The implication here is that if capitalism has been OK for me, and I enjoy a reasonable level of material comfort, then it’s fine, and for those innumerable millions all over the world living in misery, sorry but life is unfair. This view is self-centered and short-sighted. You probably would agree that we should deplore racism even if we are not a victim of it. This is ordinary moral decency. Why is social inequality any different? Because you start from the mistaken assumption that inequality is somehow an immutable characteristic of human social organization, a pessimistic and defeatist worldview with no objective, scientific basis.

The good news is that there is considerable evidence to the contrary. Of course, there are both selfish and altruistic tendencies in human behavior. The solution is to create social structures that make it difficult for the selfish and greedy impulses of a few to screw everyone else. The hope — and there is reason for hope — is that when material want is a thing of the past, the need for extreme greed will diminish and eventually fall away.

A few hundred years ago, slavery and genocide were far more common than they are today. Those who advocated for the abolition of the slave trade were derided as dreamers, or worse. Nowadays, world opinion is virtually unanimous that genocide and slavery are wrong. This is progress, and there are other examples. Human society has progressed from slavocracy to feudalism to bourgeois democracy and capitalism. Fortunately, there is no reason to believe that capitalism is the endpoint of human social evolution. Quite the opposite is true: capitalism gives every indication of coming apart at the seams. What will follow? That is the big question.

My view is that world socialist revolution is the only way forward. The resources of the planet must be brought under the democratic control of the working class — meaning the overwhelming majority of humankind — and utilized rationally to meet the needs of people and the environment, rather than pillaged for the benefit of a tiny minority at the top. If you think this is an unrealistic goal, consider the alternative.

Top ten books — because you asked for it

People on Facebook have inviting their FB friends to list the top ten books that have had the greatest impact in our lives. Some people start naming big-name classics like Cervantes, Tolstoy, Shakespeare, Joyce. This strikes me as rather uninteresting, but maybe I am just envious because I am not well-read in the classics. Others are surprisingly candid — or perhaps, naive — in listing some real crap, self-help junk, various pop-schlock titles. I guess I am somewhere between an intellectual and a moron; ignorant, but a snob.
Problem is, I can’t bring myself to do this top ten list. I have been living 50+ years and reading for so long that I no longer remember very well the books that had a great impact at the time I read them, even where their impact was indeed great. The more recently read books tend to displace the old ones. So most of my top ten would be things from the past five years or so. All right, let’s give it a try anyway:
(1) Nietszche – Thus Spoke Zarathustra. Made a huge impression on me when I was 16 years old, so it has to stay on the list. I may not have understood it deeply, but nevertheless.
(2) Juliet Schor – The Overworked American. I read it in the early 1990s and keep remembering it time and again, so it makes the list.
(3) Duke and Gross – America’s Longest War. Greatly informed my thinking about the so-called War on Drugs, which I have been observing from the perspective of a judiciary employee for the past 20 years.
(4) Mathieu RicardHappiness. Picked up a copy while looking for something to do at an airport in December 2006. The timing was perfect. It actually changed my life for the better, permanently.
(5) Michael Pollan – The Omnivore’s Dilemma. I was already leaning in the direction of a vegetarian diet, but after reading this, I changed the way I eat.
(6) The Gateless Barrier, a/k/a The Gateless Gate. I was a student at a zendo for about two and a half years, studying with a teacher. Maybe some of it was bullshit. But we went through this koan collection, and I did a lot of sitting (still do hit the mat every day). I know the exercise had a profound effect.
(7) Kurt Vonnegut – Slaughterhouse 5. I never read it until recently — a couple years ago. I think it’s one of the finest novels I have ever read.
(8) Haruki Murakami – 1Q84. It isn’t just this novel, but that it introduced me to this writer and I went on to read several more of his books. You talk about a work of fiction grabbing you in the first few pages. This one grabbed me and did not let go for the next 900+ pages. I don’t know what it is about this guy. He sees the world in a weird way that is peculiar to him, and yet… universal? “Remember: there is always only one reality.” Really?
(9) Don deLillo – Underground. The one that begins at the famous Dodgers-Giants game in 1959. Man, that was one fucking good book.
(10) Terry Eagleton – Why Marx Was Right. My father and I have a decades-long history of talking about politics, about which we generally agree, although I have moved to the left of him. He lent me this book, and it had an enormous impact. Hitherto, I had often said I would consider myself a socialist but for the fact that I had not read any Marx or Engels, much less Lenin or Trotsky. I went on to establish contact with some real, practicing Marxists. In a conversation with one of them — a particularly feisty and erudite old bastard whom I’ll call Fred — he scoffed at Why Marx Was Right, saying Eagleton was a “Catholic Marxist,” i.e., something of a joke. But this book got me started reading some of the works of Trotsky, Lenin, Marx, Engels, and finding out for myself what the political theory is. Combining that with readings of countless contemporary articles that use Marxist methods of analysis, attending some lectures, and observing world events unfold through my own eyes, my political education has advanced greatly in the past two or three years. I am a Marxist-Trotskyist. In this capitalist culture, much of what my generation has been taught about history and socialism is utter nonsense. I have developed a reasonable level of confidence in my ability to sort out the truth from the bullshit.